OSDN Git Service

contrib:
[pf3gnuchains/gcc-fork.git] / gcc / except.c
index 952021b..5c666d4 100644 (file)
@@ -1,5 +1,6 @@
 /* Implements exception handling.
-   Copyright (C) 1989, 1992-1999 Free Software Foundation, Inc.
+   Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 
+   1999, 2000 Free Software Foundation, Inc.
    Contributed by Mike Stump <mrs@cygnus.com>.
 
 This file is part of GNU CC.
@@ -408,6 +409,8 @@ Boston, MA 02111-1307, USA.  */
 #include "toplev.h"
 #include "intl.h"
 #include "obstack.h"
+#include "ggc.h"
+#include "tm_p.h"
 
 /* One to use setjmp/longjmp method of generating code for exception
    handling.  */
@@ -451,24 +454,39 @@ static rtx last_rethrow_symbol = NULL_RTX;
 
 /* Prototypes for local functions.  */
 
-static void push_eh_entry      PROTO((struct eh_stack *));
-static struct eh_entry * pop_eh_entry          PROTO((struct eh_stack *));
-static void enqueue_eh_entry   PROTO((struct eh_queue *, struct eh_entry *));
-static struct eh_entry * dequeue_eh_entry      PROTO((struct eh_queue *));
-static rtx call_get_eh_context PROTO((void));
-static void start_dynamic_cleanup              PROTO((tree, tree));
-static void start_dynamic_handler              PROTO((void));
-static void expand_rethrow     PROTO((rtx));
-static void output_exception_table_entry       PROTO((FILE *, int));
-static int can_throw           PROTO((rtx));
-static rtx scan_region         PROTO((rtx, int, int *));
-static void eh_regs            PROTO((rtx *, rtx *, rtx *, int));
-static void set_insn_eh_region PROTO((rtx *, int));
+static void push_eh_entry      PARAMS ((struct eh_stack *));
+static struct eh_entry * pop_eh_entry  PARAMS ((struct eh_stack *));
+static void enqueue_eh_entry   PARAMS ((struct eh_queue *, struct eh_entry *));
+static struct eh_entry * dequeue_eh_entry      PARAMS ((struct eh_queue *));
+static rtx call_get_eh_context PARAMS ((void));
+static void start_dynamic_cleanup      PARAMS ((tree, tree));
+static void start_dynamic_handler      PARAMS ((void));
+static void expand_rethrow     PARAMS ((rtx));
+static void output_exception_table_entry       PARAMS ((FILE *, int));
+static rtx scan_region         PARAMS ((rtx, int, int *));
+static void eh_regs            PARAMS ((rtx *, rtx *, rtx *, int));
+static void set_insn_eh_region PARAMS ((rtx *, int));
 #ifdef DONT_USE_BUILTIN_SETJMP
-static void jumpif_rtx         PROTO((rtx, rtx));
+static void jumpif_rtx         PARAMS ((rtx, rtx));
 #endif
+static void find_exception_handler_labels_1 PARAMS ((rtx));
+static void mark_eh_node        PARAMS ((struct eh_node *));
+static void mark_eh_stack       PARAMS ((struct eh_stack *));
+static void mark_eh_queue       PARAMS ((struct eh_queue *));
+static void mark_tree_label_node PARAMS ((struct label_node *));
+static void mark_func_eh_entry PARAMS ((void *));
+static rtx create_rethrow_ref  PARAMS ((int));
+static void push_entry         PARAMS ((struct eh_stack *, struct eh_entry*));
+static void receive_exception_label PARAMS ((rtx));
+static int new_eh_region_entry PARAMS ((int, rtx));
+static int find_func_region    PARAMS ((int));
+static int find_func_region_from_symbol PARAMS ((rtx));
+static void clear_function_eh_region PARAMS ((void));
+static void process_nestinfo   PARAMS ((int, eh_nesting_info *, int *));
+rtx expand_builtin_return_addr PARAMS ((enum built_in_function, int, rtx));
+static void emit_cleanup_handler PARAMS ((struct eh_entry *));
+static int eh_region_from_symbol PARAMS ((rtx));
 
-rtx expand_builtin_return_addr PROTO((enum built_in_function, int, rtx));
 \f
 /* Various support routines to manipulate the various data structures
    used by the exception handling code.  */
@@ -476,23 +494,20 @@ rtx expand_builtin_return_addr    PROTO((enum built_in_function, int, rtx));
 extern struct obstack permanent_obstack;
 
 /* Generate a SYMBOL_REF for rethrow to use */
+
 static rtx
 create_rethrow_ref (region_num)
      int region_num;
 {
   rtx def;
-  char *ptr;
+  const char *ptr;
   char buf[60];
 
-  push_obstacks_nochange ();
-  end_temporary_allocation ();
-
   ASM_GENERATE_INTERNAL_LABEL (buf, "LRTH", region_num);
-  ptr = (char *) obstack_copy0 (&permanent_obstack, buf, strlen (buf));
+  ptr = ggc_strdup (buf);
   def = gen_rtx_SYMBOL_REF (Pmode, ptr);
   SYMBOL_REF_NEED_ADJUST (def) = 1;
 
-  pop_obstacks ();
   return def;
 }
 
@@ -547,7 +562,7 @@ top_label_entry (stack)
   return (*stack)->u.tlabel;
 }
 
-/* get an exception label. These must be on the permanent obstack */
+/* Get an exception label.  */
 
 rtx
 gen_exception_label ()
@@ -576,13 +591,15 @@ push_eh_entry (stack)
   else
     entry->outer_context = create_rethrow_ref (CODE_LABEL_NUMBER (rlab));
   entry->rethrow_label = entry->outer_context;
+  entry->goto_entry_p = 0;
 
   node->entry = entry;
   node->chain = stack->top;
   stack->top = node;
 }
 
-/* push an existing entry onto a stack. */
+/* Push an existing entry onto a stack.  */
+
 static void
 push_entry (stack, entry)
      struct eh_stack *stack;
@@ -624,13 +641,9 @@ enqueue_eh_entry (queue, entry)
   node->chain = NULL;
 
   if (queue->head == NULL)
-    {
-      queue->head = node;
-    }
+    queue->head = node;
   else
-    {
-      queue->tail->chain = node;
-    }
+    queue->tail->chain = node;
   queue->tail = node;
 }
 
@@ -659,19 +672,40 @@ static void
 receive_exception_label (handler_label)
      rtx handler_label;
 {
+  rtx around_label = NULL_RTX;
+
+  if (! flag_new_exceptions || exceptions_via_longjmp)
+    {
+      around_label = gen_label_rtx ();
+      emit_jump (around_label);
+      emit_barrier ();
+    }
+
   emit_label (handler_label);
   
-#ifdef HAVE_exception_receiver
   if (! exceptions_via_longjmp)
-    if (HAVE_exception_receiver)
-      emit_insn (gen_exception_receiver ());
+    {
+#ifdef HAVE_exception_receiver
+      if (HAVE_exception_receiver)
+       emit_insn (gen_exception_receiver ());
+      else
 #endif
-
 #ifdef HAVE_nonlocal_goto_receiver
-  if (! exceptions_via_longjmp)
-    if (HAVE_nonlocal_goto_receiver)
-      emit_insn (gen_nonlocal_goto_receiver ());
+      if (HAVE_nonlocal_goto_receiver)
+       emit_insn (gen_nonlocal_goto_receiver ());
+      else
+#endif
+       { /* Nothing */ }
+    }
+  else
+    {
+#ifndef DONT_USE_BUILTIN_SETJMP
+      expand_builtin_setjmp_receiver (handler_label);
 #endif
+    }
+
+  if (around_label)
+    emit_label (around_label);
 }
 
 
@@ -679,7 +713,8 @@ struct func_eh_entry
 {
   int range_number;   /* EH region number from EH NOTE insn's.  */
   rtx rethrow_label;  /* Label for rethrow.  */
-  int rethrow_ref;    /* Is rethrow referenced?  */
+  int rethrow_ref;    /* Is rethrow_label referenced?  */
+  int emitted;        /* 1 if this entry has been emitted in assembly file.  */
   struct handler_info *handlers;
 };
 
@@ -691,10 +726,8 @@ static int current_func_eh_entry = 0;
 
 #define SIZE_FUNC_EH(X)   (sizeof (struct func_eh_entry) * X)
 
-/* Add a new eh_entry for this function, and base it off of the information
-   in the EH_ENTRY parameter. A NULL parameter is invalid. 
-   OUTER_CONTEXT is a label which is used for rethrowing. The number
-   returned is an number which uniquely identifies this exception range. */
+/* Add a new eh_entry for this function.  The number returned is an
+   number which uniquely identifies this exception range. */
 
 static int 
 new_eh_region_entry (note_eh_region, rethrow) 
@@ -706,14 +739,14 @@ new_eh_region_entry (note_eh_region, rethrow)
       if (num_func_eh_entries == 0)
         {
           function_eh_regions = 
-                        (struct func_eh_entry *) malloc (SIZE_FUNC_EH (50));
+                        (struct func_eh_entry *) xmalloc (SIZE_FUNC_EH (50));
           num_func_eh_entries = 50;
         }
       else
         {
           num_func_eh_entries  = num_func_eh_entries * 3 / 2;
           function_eh_regions = (struct func_eh_entry *) 
-            realloc (function_eh_regions, SIZE_FUNC_EH (num_func_eh_entries));
+            xrealloc (function_eh_regions, SIZE_FUNC_EH (num_func_eh_entries));
         }
     }
   function_eh_regions[current_func_eh_entry].range_number = note_eh_region;
@@ -723,7 +756,8 @@ new_eh_region_entry (note_eh_region, rethrow)
   else
     function_eh_regions[current_func_eh_entry].rethrow_label = rethrow;
   function_eh_regions[current_func_eh_entry].handlers = NULL;
-
+  function_eh_regions[current_func_eh_entry].emitted = 0;
   return current_func_eh_entry++;
 }
 
@@ -741,6 +775,12 @@ add_new_handler (region, newhandler)
 {
   struct handler_info *last;
 
+  /* If find_func_region returns -1, callers might attempt to pass us
+     this region number.  If that happens, something has gone wrong;
+     -1 is never a valid region.  */
+  if (region == -1)
+    abort ();
+
   newhandler->next = NULL;
   last = function_eh_regions[region].handlers;
   if (last == NULL)
@@ -807,10 +847,7 @@ find_all_handler_type_matches (array)
     return 0;
 
   max_ptr = 100;
-  ptr = (void **)malloc (max_ptr * sizeof (void *));
-
-  if (ptr == NULL)
-    return 0;
+  ptr = (void **) xmalloc (max_ptr * sizeof (void *));
 
   for (x = 0 ; x < current_func_eh_entry; x++)
     {
@@ -834,15 +871,19 @@ find_all_handler_type_matches (array)
               if (n_ptr >= max_ptr) 
                 {
                   max_ptr += max_ptr / 2;
-                  ptr = (void **)realloc (ptr, max_ptr * sizeof (void *));
-                  if (ptr == NULL)
-                    return 0;
+                  ptr = (void **) xrealloc (ptr, max_ptr * sizeof (void *));
                 }
               ptr[n_ptr] = val;
               n_ptr++;
             }
         }
     }
+
+  if (n_ptr == 0)
+    {
+      free (ptr);
+      ptr = NULL;
+    }
   *array = ptr;
   return n_ptr;
 }
@@ -856,7 +897,7 @@ get_new_handler (handler, typeinfo)
      void *typeinfo;
 {
   struct handler_info* ptr;
-  ptr = (struct handler_info *) malloc (sizeof (struct handler_info));
+  ptr = (struct handler_info *) xmalloc (sizeof (struct handler_info));
   ptr->handler_label = handler;
   ptr->handler_number = CODE_LABEL_NUMBER (handler);
   ptr->type_info = typeinfo;
@@ -868,9 +909,9 @@ get_new_handler (handler, typeinfo)
 
 
 /* Find the index in function_eh_regions associated with a NOTE region. If
-   the region cannot be found, a -1 is returned. This should never happen! */
+   the region cannot be found, a -1 is returned.  */
 
-int 
+static int 
 find_func_region (insn_region)
      int insn_region;
 {
@@ -888,7 +929,10 @@ struct handler_info *
 get_first_handler (region)
      int region;
 {
-  return function_eh_regions[find_func_region (region)].handlers;
+  int r = find_func_region (region);
+  if (r == -1)
+    abort ();
+  return function_eh_regions[r].handlers;
 }
 
 /* Clean out the function_eh_region table and free all memory */
@@ -904,7 +948,8 @@ clear_function_eh_region ()
         next = ptr->next;
         free (ptr);
       }
-  free (function_eh_regions);
+  if (function_eh_regions)
+    free (function_eh_regions);
   num_func_eh_entries  = 0;
   current_func_eh_entry = 0;
 }
@@ -945,7 +990,8 @@ duplicate_eh_handlers (old_note_eh_region, new_note_eh_region, map)
 
 
 /* Given a rethrow symbol, find the EH region number this is for. */
-int 
+
+static int 
 eh_region_from_symbol (sym)
      rtx sym;
 {
@@ -958,17 +1004,31 @@ eh_region_from_symbol (sym)
   return -1;
 }
 
+/* Like find_func_region, but using the rethrow symbol for the region
+   rather than the region number itself.  */
+
+static int
+find_func_region_from_symbol (sym)
+     rtx sym;
+{
+  return find_func_region (eh_region_from_symbol (sym));
+}
 
 /* When inlining/unrolling, we have to map the symbols passed to
    __rethrow as well. This performs the remap. If a symbol isn't foiund,
    the original one is returned. This is not an efficient routine,
    so don't call it on everything!! */
+
 rtx 
 rethrow_symbol_map (sym, map)
      rtx sym;
      rtx (*map) PARAMS ((rtx));
 {
   int x, y;
+
+  if (! flag_new_exceptions)
+    return sym;
+
   for (x = 0; x < current_func_eh_entry; x++)
     if (function_eh_regions[x].rethrow_label == sym)
       {
@@ -989,6 +1049,10 @@ rethrow_symbol_map (sym, map)
   return sym;
 }
 
+/* Returns nonzero if the rethrow label for REGION is referenced
+   somewhere (i.e. we rethrow out of REGION or some other region
+   masquerading as REGION).  */
+
 int 
 rethrow_used (region)
      int region;
@@ -1057,16 +1121,19 @@ add_partial_entry (handler)
 {
   expand_eh_region_start ();
 
-  /* Make sure the entry is on the correct obstack.  */
-  push_obstacks_nochange ();
-  resume_temporary_allocation ();
-
   /* Because this is a cleanup action, we may have to protect the handler
      with __terminate.  */
   handler = protect_with_terminate (handler);
 
-  protect_list = tree_cons (NULL_TREE, handler, protect_list);
-  pop_obstacks ();
+  /* For backwards compatibility, we allow callers to omit calls to
+     begin_protect_partials for the outermost region.  So, we must
+     explicitly do so here.  */
+  if (!protect_list)
+    begin_protect_partials ();
+
+  /* Add this entry to the front of the list.  */
+  TREE_VALUE (protect_list) 
+    = tree_cons (NULL_TREE, handler, TREE_VALUE (protect_list));
 }
 
 /* Emit code to get EH context to current function.  */
@@ -1081,8 +1148,6 @@ call_get_eh_context ()
     {
       tree fntype;
       fn = get_identifier ("__get_eh_context");
-      push_obstacks_nochange ();
-      end_temporary_allocation ();
       fntype = build_pointer_type (build_pointer_type
                                   (build_pointer_type (void_type_node)));
       fntype = build_function_type (fntype, NULL_TREE);
@@ -1091,9 +1156,10 @@ call_get_eh_context ()
       TREE_PUBLIC (fn) = 1;
       DECL_ARTIFICIAL (fn) = 1;
       TREE_READONLY (fn) = 1;
-      make_decl_rtl (fn, NULL_PTR, 1);
+      make_decl_rtl (fn, NULL_PTR);
       assemble_external (fn);
-      pop_obstacks ();
+
+      ggc_add_tree_root (&fn, 1);
     }
 
   expr = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (fn)), fn);
@@ -1259,14 +1325,19 @@ static void
 start_dynamic_handler ()
 {
   rtx dhc, dcc;
-  rtx x, arg, buf;
+  rtx arg, buf;
   int size;
 
 #ifndef DONT_USE_BUILTIN_SETJMP
   /* The number of Pmode words for the setjmp buffer, when using the
-     builtin setjmp/longjmp, see expand_builtin, case
-     BUILT_IN_LONGJMP.  */
-  size = 5;
+     builtin setjmp/longjmp, see expand_builtin, case BUILT_IN_LONGJMP.  */
+  /* We use 2 words here before calling expand_builtin_setjmp.
+     expand_builtin_setjmp uses 2 words, and then calls emit_stack_save.
+     emit_stack_save needs space of size STACK_SAVEAREA_MODE (SAVE_NONLOCAL).
+     Subtract one, because the assign_stack_local call below adds 1.  */
+  size = (2 + 2 + (GET_MODE_SIZE (STACK_SAVEAREA_MODE (SAVE_NONLOCAL))
+                  / GET_MODE_SIZE (Pmode))
+         - 1);
 #else
 #ifdef JMP_BUF_SIZE
   size = JMP_BUF_SIZE;
@@ -1301,18 +1372,17 @@ start_dynamic_handler ()
   buf = plus_constant (XEXP (arg, 0), GET_MODE_SIZE (Pmode)*2);
 
 #ifdef DONT_USE_BUILTIN_SETJMP
-  x = emit_library_call_value (setjmp_libfunc, NULL_RTX, 1, SImode, 1,
-                              buf, Pmode);
-  /* If we come back here for a catch, transfer control to the handler.  */
-  jumpif_rtx (x, ehstack.top->entry->exception_handler_label);
-#else
   {
-    /* A label to continue execution for the no exception case.  */
-    rtx noex = gen_label_rtx();
-    x = expand_builtin_setjmp (buf, NULL_RTX, noex,
-                              ehstack.top->entry->exception_handler_label);
-    emit_label (noex);
+    rtx x;
+    x = emit_library_call_value (setjmp_libfunc, NULL_RTX, LCT_CONST,
+                                TYPE_MODE (integer_type_node), 1,
+                                buf, Pmode);
+    /* If we come back here for a catch, transfer control to the handler.  */
+    jumpif_rtx (x, ehstack.top->entry->exception_handler_label);
   }
+#else
+  expand_builtin_setjmp_setup (buf,
+                              ehstack.top->entry->exception_handler_label);
 #endif
 
   /* We are committed to this, so update the handler chain.  */
@@ -1366,8 +1436,7 @@ expand_eh_region_start_tree (decl, cleanup)
 
          /* is the second argument 2?  */
          && TREE_CODE (TREE_VALUE (args)) == INTEGER_CST
-         && TREE_INT_CST_LOW (TREE_VALUE (args)) == 2
-         && TREE_INT_CST_HIGH (TREE_VALUE (args)) == 0
+         && compare_tree_int (TREE_VALUE (args), 2) == 0
 
          /* Make sure there are no other arguments.  */
          && TREE_CHAIN (args) == NULL_TREE)
@@ -1404,7 +1473,7 @@ expand_eh_region_start_for_decl (decl)
   /* We need a new block to record the start and end of the
      dynamic handler chain.  We also want to prevent jumping into
      a try block.  */
-  expand_start_bindings (0);
+  expand_start_bindings (2);
 
   /* But we don't need or want a new temporary level.  */
   pop_temp_slots ();
@@ -1423,7 +1492,7 @@ expand_eh_region_start_for_decl (decl)
 
   push_eh_entry (&ehstack);
   note = emit_note (NULL_PTR, NOTE_INSN_EH_REGION_BEG);
-  NOTE_BLOCK_NUMBER (note)
+  NOTE_EH_HANDLER (note)
     = CODE_LABEL_NUMBER (ehstack.top->entry->exception_handler_label);
   if (exceptions_via_longjmp)
     start_dynamic_handler ();
@@ -1453,6 +1522,7 @@ expand_eh_region_end (handler)
      tree handler;
 {
   struct eh_entry *entry;
+  struct eh_node *node;
   rtx note;
   int ret, r;
 
@@ -1462,7 +1532,7 @@ expand_eh_region_end (handler)
   entry = pop_eh_entry (&ehstack);
 
   note = emit_note (NULL_PTR, NOTE_INSN_EH_REGION_END);
-  ret = NOTE_BLOCK_NUMBER (note)
+  ret = NOTE_EH_HANDLER (note)
     = CODE_LABEL_NUMBER (entry->exception_handler_label);
   if (exceptions_via_longjmp == 0 && ! flag_new_exceptions
       /* We share outer_context between regions; only emit it once.  */
@@ -1484,9 +1554,9 @@ expand_eh_region_end (handler)
   entry->finalization = handler;
 
   /* create region entry in final exception table */
-  r = new_eh_region_entry (NOTE_BLOCK_NUMBER (note), entry->rethrow_label);
+  r = new_eh_region_entry (NOTE_EH_HANDLER (note), entry->rethrow_label);
 
-  enqueue_eh_entry (&ehqueue, entry);
+  enqueue_eh_entry (ehqueue, entry);
 
   /* If we have already started ending the bindings, don't recurse.  */
   if (is_eh_region ())
@@ -1501,6 +1571,21 @@ expand_eh_region_end (handler)
 
       expand_end_bindings (NULL_TREE, 0, 0);
     }
+
+  /* Go through the goto handlers in the queue, emitting their
+     handlers if we now have enough information to do so.  */
+  for (node = ehqueue->head; node; node = node->chain)
+    if (node->entry->goto_entry_p 
+       && node->entry->outer_context == entry->rethrow_label)
+      emit_cleanup_handler (node->entry);
+
+  /* We can't emit handlers for goto entries until their scopes are
+     complete because we don't know where they need to rethrow to,
+     yet.  */
+  if (entry->finalization != integer_zero_node 
+      && (!entry->goto_entry_p 
+         || find_func_region_from_symbol (entry->outer_context) != -1))
+    emit_cleanup_handler (entry);
 }
 
 /* End the EH region for a goto fixup.  We only need them in the region-based
@@ -1513,6 +1598,8 @@ expand_fixup_region_start ()
     return;
 
   expand_eh_region_start ();
+  /* Mark this entry as the entry for a goto.  */
+  ehstack.top->entry->goto_entry_p = 1;
 }
 
 /* End the EH region for a goto fixup.  CLEANUP is the cleanup we just
@@ -1532,7 +1619,7 @@ expand_fixup_region_end (cleanup)
   for (node = ehstack.top; node && node->entry->finalization != cleanup; )
     node = node->chain;
   if (node == 0)
-    for (node = ehqueue.head; node && node->entry->finalization != cleanup; )
+    for (node = ehqueue->head; node && node->entry->finalization != cleanup; )
       node = node->chain;
   if (node == 0)
     abort ();
@@ -1544,8 +1631,11 @@ expand_fixup_region_end (cleanup)
      and we could get an infinte loop when it tried to rethrow, or just
      generally incorrect execution following a throw. */
 
-  dont_issue = ((INSN_UID (node->entry->outer_context) == 0) 
-            && (ehstack.top->entry != node->entry));
+  if (flag_new_exceptions)
+    dont_issue = 0;
+  else
+    dont_issue = ((INSN_UID (node->entry->outer_context) == 0) 
+                 && (ehstack.top->entry != node->entry));
 
   ehstack.top->entry->outer_context = node->entry->outer_context;
 
@@ -1565,16 +1655,7 @@ expand_fixup_region_end (cleanup)
 }
 
 /* If we are using the setjmp/longjmp EH codegen method, we emit a
-   call to __sjthrow.
-
-   Otherwise, we emit a call to __throw and note that we threw
-   something, so we know we need to generate the necessary code for
-   __throw.
-
-   Before invoking throw, the __eh_pc variable must have been set up
-   to contain the PC being thrown from. This address is used by
-   __throw to determine which exception region (if any) is
-   responsible for handling the exception.  */
+   call to __sjthrow.  Otherwise, we emit a call to __throw.  */
 
 void
 emit_throw ()
@@ -1611,33 +1692,14 @@ expand_leftover_cleanups ()
 {
   struct eh_entry *entry;
 
-  while ((entry = dequeue_eh_entry (&ehqueue)) != 0)
+  for (entry = dequeue_eh_entry (ehqueue); 
+       entry;
+       entry = dequeue_eh_entry (ehqueue))
     {
-      rtx prev;
-
-      /* A leftover try block. Shouldn't be one here.  */
+      /* A leftover try block.  Shouldn't be one here.  */
       if (entry->finalization == integer_zero_node)
        abort ();
 
-      /* Output the label for the start of the exception handler.  */
-
-      receive_exception_label (entry->exception_handler_label);
-
-      /* register a handler for this cleanup region */
-      add_new_handler (
-        find_func_region (CODE_LABEL_NUMBER (entry->exception_handler_label)), 
-        get_new_handler (entry->exception_handler_label, NULL));
-
-      /* And now generate the insns for the handler.  */
-      expand_expr (entry->finalization, const0_rtx, VOIDmode, 0);
-
-      prev = get_last_insn ();
-      if (prev == NULL || GET_CODE (prev) != BARRIER)
-       /* Emit code to throw to the outer context if we fall off
-          the end of the handler.  */
-       expand_rethrow (entry->outer_context);
-
-      do_pending_stack_adjust ();
       free (entry);
     }
 }
@@ -1692,7 +1754,10 @@ start_catch_handler (rtime)
       rtx call_rtx, rtime_address;
 
       if (catchstack.top->entry->false_label != NULL_RTX)
-        fatal ("Compiler Bug: Never issued previous false_label");
+       {
+         error ("Never issued previous false_label");
+         abort ();
+       }
       catchstack.top->entry->false_label = gen_exception_label ();
 
       rtime_address = expand_expr (rtime, NULL_RTX, Pmode, EXPAND_INITIALIZER);
@@ -1703,7 +1768,9 @@ start_catch_handler (rtime)
 
       /* Now issue the call, and branch around handler if needed */
       call_rtx = emit_library_call_value (eh_rtime_match_libfunc, NULL_RTX, 
-                                          0, SImode, 1, rtime_address, Pmode);
+                                          LCT_NORMAL,
+                                         TYPE_MODE (integer_type_node),
+                                         1, rtime_address, Pmode);
 
       /* Did the function return true? */
       emit_cmp_and_jump_insns (call_rtx, const0_rtx, EQ, NULL_RTX,
@@ -1736,6 +1803,86 @@ end_catch_handler ()
   catchstack.top->entry->false_label = NULL_RTX;
 }
 
+/* Save away the current ehqueue.  */
+
+void 
+push_ehqueue ()
+{
+  struct eh_queue *q;
+  q = (struct eh_queue *) xcalloc (1, sizeof (struct eh_queue));
+  q->next = ehqueue;
+  ehqueue = q;
+}
+
+/* Restore a previously pushed ehqueue.  */
+
+void
+pop_ehqueue ()
+{
+  struct eh_queue *q;
+  expand_leftover_cleanups ();
+  q = ehqueue->next;
+  free (ehqueue);
+  ehqueue = q;
+}
+
+/* Emit the handler specified by ENTRY.  */
+
+static void
+emit_cleanup_handler (entry)
+  struct eh_entry *entry;
+{
+  rtx prev;
+  rtx handler_insns;
+
+  /* Since the cleanup could itself contain try-catch blocks, we
+     squirrel away the current queue and replace it when we are done
+     with this function.  */
+  push_ehqueue ();
+
+  /* Put these handler instructions in a sequence.  */
+  do_pending_stack_adjust ();
+  start_sequence ();
+
+  /* Emit the label for the cleanup handler for this region, and
+     expand the code for the handler.
+     
+     Note that a catch region is handled as a side-effect here; for a
+     try block, entry->finalization will contain integer_zero_node, so
+     no code will be generated in the expand_expr call below. But, the
+     label for the handler will still be emitted, so any code emitted
+     after this point will end up being the handler.  */
+      
+  receive_exception_label (entry->exception_handler_label);
+
+  /* register a handler for this cleanup region */
+  add_new_handler (find_func_region (CODE_LABEL_NUMBER (entry->exception_handler_label)), 
+                  get_new_handler (entry->exception_handler_label, NULL));
+
+  /* And now generate the insns for the cleanup handler.  */
+  expand_expr (entry->finalization, const0_rtx, VOIDmode, 0);
+
+  prev = get_last_insn ();
+  if (prev == NULL || GET_CODE (prev) != BARRIER)
+    /* Code to throw out to outer context when we fall off end of the
+       handler. We can't do this here for catch blocks, so it's done
+       in expand_end_all_catch instead.  */
+    expand_rethrow (entry->outer_context);
+
+  /* Finish this sequence.  */
+  do_pending_stack_adjust ();
+  handler_insns = get_insns ();
+  end_sequence ();
+
+  /* And add it to the CATCH_CLAUSES.  */
+  push_to_full_sequence (catch_clauses, catch_clauses_last);
+  emit_insns (handler_insns);
+  end_full_sequence (&catch_clauses, &catch_clauses_last);
+
+  /* Now we've left the handler.  */
+  pop_ehqueue ();
+}
+
 /* Generate RTL for the start of a group of catch clauses. 
 
    It is responsible for starting a new instruction sequence for the
@@ -1774,48 +1921,18 @@ expand_start_all_catch ()
      the handlers in this handler-seq.  */
   start_sequence ();
 
-  entry = dequeue_eh_entry (&ehqueue);
-  for ( ; entry->finalization != integer_zero_node;
-                                 entry = dequeue_eh_entry (&ehqueue))
-    {
-      rtx prev;
-
-      /* Emit the label for the cleanup handler for this region, and
-        expand the code for the handler. 
-
-        Note that a catch region is handled as a side-effect here;
-        for a try block, entry->finalization will contain
-        integer_zero_node, so no code will be generated in the
-        expand_expr call below. But, the label for the handler will
-        still be emitted, so any code emitted after this point will
-        end up being the handler.  */
-      
-      receive_exception_label (entry->exception_handler_label);
-
-      /* register a handler for this cleanup region */
-      add_new_handler (
-        find_func_region (CODE_LABEL_NUMBER (entry->exception_handler_label)), 
-        get_new_handler (entry->exception_handler_label, NULL));
-
-      /* And now generate the insns for the cleanup handler.  */
-      expand_expr (entry->finalization, const0_rtx, VOIDmode, 0);
-
-      prev = get_last_insn ();
-      if (prev == NULL || GET_CODE (prev) != BARRIER)
-       /* Code to throw out to outer context when we fall off end
-          of the handler. We can't do this here for catch blocks,
-          so it's done in expand_end_all_catch instead.  */
-       expand_rethrow (entry->outer_context);
-
-      do_pending_stack_adjust ();
-      free (entry);
-    }
+  /* Throw away entries in the queue that we won't need anymore.  We
+     need entries for regions that have ended but to which there might
+     still be gotos pending.  */
+  for (entry = dequeue_eh_entry (ehqueue); 
+       entry->finalization != integer_zero_node;
+       entry = dequeue_eh_entry (ehqueue))
+    free (entry);
 
   /* At this point, all the cleanups are done, and the ehqueue now has
      the current exception region at its head. We dequeue it, and put it
      on the catch stack. */
-
-    push_entry (&catchstack, entry);
+  push_entry (&catchstack, entry);
 
   /* If we are not doing setjmp/longjmp EH, because we are reordered
      out of line, we arrange to rethrow in the outer context.  We need to
@@ -1882,10 +1999,9 @@ expand_end_all_catch ()
   pop_label_entry (&outer_context_label_stack);
 
   /* Add the new sequence of catches to the main one for this function.  */
-  push_to_sequence (catch_clauses);
+  push_to_full_sequence (catch_clauses, catch_clauses_last);
   emit_insns (new_catch_clause);
-  catch_clauses = get_insns ();
-  end_sequence ();
+  end_full_sequence (&catch_clauses, &catch_clauses_last);
   
   /* Here we fall through into the continuation code.  */
 }
@@ -1901,12 +2017,16 @@ expand_rethrow (label)
   else
     if (flag_new_exceptions)
       {
-       rtx insn, val;
+       rtx insn;
        int region;
        if (label == NULL_RTX)
          label = last_rethrow_symbol;
        emit_library_call (rethrow_libfunc, 0, VOIDmode, 1, label, Pmode);
        region = find_func_region (eh_region_from_symbol (label));
+       /* If the region is -1, it doesn't exist yet.  We shouldn't be
+          trying to rethrow there yet.  */
+       if (region == -1)
+         abort ();
        function_eh_regions[region].rethrow_ref = 1;
 
        /* Search backwards for the actual call insn.  */
@@ -1924,17 +2044,37 @@ expand_rethrow (label)
       emit_jump (label);
 }
 
+/* Begin a region that will contain entries created with
+   add_partial_entry.  */
+
+void
+begin_protect_partials ()
+{
+  /* Push room for a new list.  */
+  protect_list = tree_cons (NULL_TREE, NULL_TREE, protect_list);
+}
+
 /* End all the pending exception regions on protect_list. The handlers
    will be emitted when expand_leftover_cleanups is invoked.  */
 
 void
 end_protect_partials ()
 {
-  while (protect_list)
-    {
-      expand_eh_region_end (TREE_VALUE (protect_list));
-      protect_list = TREE_CHAIN (protect_list);
-    }
+  tree t;
+  
+  /* For backwards compatibility, we allow callers to omit the call to
+     begin_protect_partials for the outermost region.  So,
+     PROTECT_LIST may be NULL.  */
+  if (!protect_list)
+    return;
+
+  /* End all the exception regions.  */
+  for (t = TREE_VALUE (protect_list); t; t = TREE_CHAIN (t))
+    expand_eh_region_end (TREE_VALUE (t));
+
+  /* Pop the topmost entry.  */
+  protect_list = TREE_CHAIN (protect_list);
+  
 }
 
 /* Arrange for __terminate to be called if there is an unhandled throw
@@ -1951,10 +2091,6 @@ protect_with_terminate (e)
     {
       tree handler, result;
 
-      /* All cleanups must be on the function_obstack.  */
-      push_obstacks_nochange ();
-      resume_temporary_allocation ();
-
       handler = make_node (RTL_EXPR);
       TREE_TYPE (handler) = void_type_node;
       RTL_EXPR_RTL (handler) = const0_rtx;
@@ -1972,8 +2108,6 @@ protect_with_terminate (e)
       TREE_THIS_VOLATILE (result) = TREE_THIS_VOLATILE (e);
       TREE_READONLY (result) = TREE_READONLY (e);
 
-      pop_obstacks ();
-
       e = result;
     }
 
@@ -1998,7 +2132,7 @@ static int eh_table_max_size = 0;
 
    Called from final_scan_insn when a NOTE_INSN_EH_REGION_BEG is seen.
    (Or NOTE_INSN_EH_REGION_END sometimes)
-   N is the NOTE_BLOCK_NUMBER of the note, which comes from the code
+   N is the NOTE_EH_HANDLER of the note, which comes from the code
    label number of the exception handler for the region.  */
 
 void
@@ -2025,6 +2159,24 @@ add_eh_table_entry (n)
        }
     }
   eh_table[eh_table_size++] = n;
+  
+  if (flag_new_exceptions)
+    {
+      /* We will output the exception table late in the compilation. That
+         references type_info objects which should have already been output
+         by that time. We explicitly mark those objects as being
+         referenced now so we know to emit them.  */
+      struct handler_info *handler = get_first_handler (n);
+      
+      for (; handler; handler = handler->next)
+        if (handler->type_info && handler->type_info != CATCH_ALL_TYPE)
+          {
+            tree tinfo = (tree)handler->type_info;
+
+            tinfo = TREE_OPERAND (tinfo, 0);
+            TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (tinfo)) = 1;
+          }
+    }
 #endif
 }
 
@@ -2059,14 +2211,16 @@ output_exception_table_entry (file, n)
   int index = find_func_region (n);
   rtx rethrow;
   
- /* form and emit the rethrow label, if needed  */
-  rethrow = function_eh_regions[index].rethrow_label;
-  if (rethrow != NULL_RTX && !flag_new_exceptions)
-      rethrow = NULL_RTX;
-  if (rethrow != NULL_RTX && handler == NULL)
-    if (! function_eh_regions[index].rethrow_ref)
-      rethrow = NULL_RTX;
+  /* Form and emit the rethrow label, if needed  */
+  if (flag_new_exceptions
+      && (handler || function_eh_regions[index].rethrow_ref))
+    rethrow = function_eh_regions[index].rethrow_label;
+  else
+    rethrow = NULL_RTX;
 
+  if (function_eh_regions[index].emitted)
+    return;
+  function_eh_regions[index].emitted  = 1;
 
   for ( ; handler != NULL || rethrow != NULL_RTX; handler = handler->next)
     {
@@ -2074,34 +2228,34 @@ output_exception_table_entry (file, n)
       if (rethrow != NULL_RTX && (handler == NULL || handler->next == NULL))
         {
           ASM_GENERATE_INTERNAL_LABEL (buf, "LRTH", n);
-          assemble_label(buf);
+          assemble_eh_label(buf);
           rethrow = NULL_RTX;
         }
 
       ASM_GENERATE_INTERNAL_LABEL (buf, "LEHB", n);
       sym = gen_rtx_SYMBOL_REF (Pmode, buf);
-      assemble_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1);
+      assemble_eh_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1);
 
       ASM_GENERATE_INTERNAL_LABEL (buf, "LEHE", n);
       sym = gen_rtx_SYMBOL_REF (Pmode, buf);
-      assemble_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1);
+      assemble_eh_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1);
       
       if (handler == NULL)
-        assemble_integer (GEN_INT (0), POINTER_SIZE / BITS_PER_UNIT, 1);
+        assemble_eh_integer (GEN_INT (0), POINTER_SIZE / BITS_PER_UNIT, 1);
       else
         {
           ASM_GENERATE_INTERNAL_LABEL (buf, "L", handler->handler_number);
           sym = gen_rtx_SYMBOL_REF (Pmode, buf);
-          assemble_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1);
+          assemble_eh_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1);
         }
 
       if (flag_new_exceptions)
         {
           if (handler == NULL || handler->type_info == NULL)
-            assemble_integer (const0_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
+            assemble_eh_integer (const0_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
           else
             if (handler->type_info == CATCH_ALL_TYPE)
-              assemble_integer (GEN_INT (CATCH_ALL_TYPE), 
+              assemble_eh_integer (GEN_INT (CATCH_ALL_TYPE), 
                                              POINTER_SIZE / BITS_PER_UNIT, 1);
             else
               output_constant ((tree)(handler->type_info), 
@@ -2135,61 +2289,101 @@ set_exception_version_code (code)
   version_code = code;
 }
 
-
+/* Free the EH table structures.  */
 void
-output_exception_table ()
+free_exception_table ()
+{
+  if (eh_table)
+    free (eh_table);
+  clear_function_eh_region ();
+}
+  
+/* Output the common content of an exception table.  */
+void
+output_exception_table_data ()
 {
   int i;
   char buf[256];
   extern FILE *asm_out_file;
 
-  if (! doing_eh (0) || ! eh_table)
-    return;
-
-  exception_section ();
-
-  /* Beginning marker for table.  */
-  assemble_align (GET_MODE_ALIGNMENT (ptr_mode));
-  assemble_label ("__EXCEPTION_TABLE__");
-
   if (flag_new_exceptions)
     {
-      assemble_integer (GEN_INT (NEW_EH_RUNTIME), 
+      assemble_eh_integer (GEN_INT (NEW_EH_RUNTIME), 
                                         POINTER_SIZE / BITS_PER_UNIT, 1);
-      assemble_integer (GEN_INT (language_code), 2 , 1); 
-      assemble_integer (GEN_INT (version_code), 2 , 1);
+      assemble_eh_integer (GEN_INT (language_code), 2 , 1); 
+      assemble_eh_integer (GEN_INT (version_code), 2 , 1);
 
       /* Add enough padding to make sure table aligns on a pointer boundry. */
       i = GET_MODE_ALIGNMENT (ptr_mode) / BITS_PER_UNIT - 4;
       for ( ; i < 0; i = i + GET_MODE_ALIGNMENT (ptr_mode) / BITS_PER_UNIT)
         ;
       if (i != 0)
-        assemble_integer (const0_rtx, i , 1);
+        assemble_eh_integer (const0_rtx, i , 1);
 
-      /* Generate the label for offset calculations on rethrows */
+      /* Generate the label for offset calculations on rethrows */
       ASM_GENERATE_INTERNAL_LABEL (buf, "LRTH", 0);
-      assemble_label(buf);
+      assemble_eh_label(buf);
     }
 
   for (i = 0; i < eh_table_size; ++i)
     output_exception_table_entry (asm_out_file, eh_table[i]);
 
-  free (eh_table);
-  clear_function_eh_region ();
+}
+
+/* Output an exception table for the entire compilation unit.  */
+void
+output_exception_table ()
+{
+  char buf[256];
+  extern FILE *asm_out_file;
+
+  if (! doing_eh (0) || ! eh_table)
+    return;
+
+  exception_section ();
+
+  /* Beginning marker for table.  */
+  assemble_eh_align (GET_MODE_ALIGNMENT (ptr_mode));
+  assemble_eh_label ("__EXCEPTION_TABLE__");
+
+  output_exception_table_data ();
 
   /* Ending marker for table.  */
   /* Generate the label for end of table. */
   ASM_GENERATE_INTERNAL_LABEL (buf, "LRTH", CODE_LABEL_NUMBER (final_rethrow));
-  assemble_label(buf);
-  assemble_integer (constm1_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
+  assemble_eh_label(buf);
+  assemble_eh_integer (constm1_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
 
-  /* for binary compatability, the old __throw checked the second
+  /* For binary compatibility, the old __throw checked the second
      position for a -1, so we should output at least 2 -1's */
   if (! flag_new_exceptions)
-    assemble_integer (constm1_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
+    assemble_eh_integer (constm1_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
 
   putc ('\n', asm_out_file);           /* blank line */
 }
+
+/* Used by the ia64 unwind format to output data for an individual 
+   function.  */
+void
+output_function_exception_table ()
+{
+  extern FILE *asm_out_file;
+
+  if (! doing_eh (0) || ! eh_table)
+    return;
+
+#ifdef HANDLER_SECTION
+  HANDLER_SECTION;
+#endif
+
+  output_exception_table_data ();
+
+  /* Ending marker for table.  */
+  assemble_eh_integer (constm1_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
+
+  putc ('\n', asm_out_file);           /* blank line */
+}
+
 \f
 /* Emit code to get EH context.
    
@@ -2231,45 +2425,28 @@ emit_eh_context ()
            end_sequence ();
 
            emit_insns_before (insns, insn);
-
-            /* At -O0, we must make the context register stay alive so
-               that the stupid.c register allocator doesn't get confused. */
-            if (obey_regdecls != 0)
-              {
-                insns = gen_rtx_USE (GET_MODE (XEXP (reg,0)), XEXP (reg,0));
-                emit_insn_before (insns, get_last_insn ());
-              }
          }
       }
 }
 
-/* Scan the current insns and build a list of handler labels. The
-   resulting list is placed in the global variable exception_handler_labels.
-
-   It is called after the last exception handling region is added to
-   the current function (when the rtl is almost all built for the
-   current function) and before the jump optimization pass.  */
+/* Scan the insn chain F and build a list of handler labels. The
+   resulting list is placed in the global variable exception_handler_labels.  */
 
-void
-find_exception_handler_labels ()
+static void
+find_exception_handler_labels_1 (f)
+     rtx f;
 {
   rtx insn;
 
-  exception_handler_labels = NULL_RTX;
-
-  /* If we aren't doing exception handling, there isn't much to check.  */
-  if (! doing_eh (0))
-    return;
-
   /* For each start of a region, add its label to the list.  */
 
-  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+  for (insn = f; insn; insn = NEXT_INSN (insn))
     {
       struct handler_info* ptr;
       if (GET_CODE (insn) == NOTE
          && NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG)
        {
-          ptr = get_first_handler (NOTE_BLOCK_NUMBER (insn));
+          ptr = get_first_handler (NOTE_EH_HANDLER (insn));
           for ( ; ptr; ptr = ptr->next) 
             {
               /* make sure label isn't in the list already */
@@ -2282,9 +2459,34 @@ find_exception_handler_labels ()
                                ptr->handler_label, exception_handler_labels);
             }
        }
+      else if (GET_CODE (insn) == CALL_INSN
+              && GET_CODE (PATTERN (insn)) == CALL_PLACEHOLDER)
+       {
+         find_exception_handler_labels_1 (XEXP (PATTERN (insn), 0));
+         find_exception_handler_labels_1 (XEXP (PATTERN (insn), 1));
+         find_exception_handler_labels_1 (XEXP (PATTERN (insn), 2));
+       }
     }
 }
 
+/* Scan the current insns and build a list of handler labels. The
+   resulting list is placed in the global variable exception_handler_labels.
+
+   It is called after the last exception handling region is added to
+   the current function (when the rtl is almost all built for the
+   current function) and before the jump optimization pass.  */
+void
+find_exception_handler_labels ()
+{
+  exception_handler_labels = NULL_RTX;
+
+  /* If we aren't doing exception handling, there isn't much to check.  */
+  if (! doing_eh (0))
+    return;
+
+  find_exception_handler_labels_1 (get_insns ());
+}     
+
 /* Return a value of 1 if the parameter label number is an exception handler
    label. Return 0 otherwise. */
 
@@ -2327,7 +2529,114 @@ check_exception_handler_labels ()
     }
 
 }
-\f
+
+/* Mark the children of NODE for GC.  */
+
+static void
+mark_eh_node (node)
+     struct eh_node *node;
+{
+  while (node)
+    {
+      if (node->entry)
+       {
+         ggc_mark_rtx (node->entry->outer_context);
+         ggc_mark_rtx (node->entry->exception_handler_label);
+         ggc_mark_tree (node->entry->finalization);
+         ggc_mark_rtx (node->entry->false_label);
+         ggc_mark_rtx (node->entry->rethrow_label);
+       }
+      node = node ->chain;
+    }
+}
+
+/* Mark S for GC.  */
+
+static void
+mark_eh_stack (s)
+     struct eh_stack *s;
+{
+  if (s)
+    mark_eh_node (s->top);
+}
+
+/* Mark Q for GC.  */
+
+static void
+mark_eh_queue (q)
+     struct eh_queue *q;
+{
+  while (q)
+    {
+      mark_eh_node (q->head);
+      q = q->next;
+    }
+}
+
+/* Mark NODE for GC.  A label_node contains a union containing either
+   a tree or an rtx.  This label_node will contain a tree.  */
+
+static void
+mark_tree_label_node (node)
+     struct label_node *node;
+{
+  while (node)
+    {
+      ggc_mark_tree (node->u.tlabel);
+      node = node->chain;
+    }
+}
+
+/* Mark EH for GC.  */
+
+void
+mark_eh_status (eh)
+     struct eh_status *eh;
+{
+  if (eh == 0)
+    return;
+
+  mark_eh_stack (&eh->x_ehstack);
+  mark_eh_stack (&eh->x_catchstack);
+  mark_eh_queue (eh->x_ehqueue);
+  ggc_mark_rtx (eh->x_catch_clauses);
+
+  if (lang_mark_false_label_stack)
+    (*lang_mark_false_label_stack) (eh->x_false_label_stack);
+  mark_tree_label_node (eh->x_caught_return_label_stack);
+
+  ggc_mark_tree (eh->x_protect_list);
+  ggc_mark_rtx (eh->ehc);
+  ggc_mark_rtx (eh->x_eh_return_stub_label);
+}
+
+/* Mark ARG (which is really a struct func_eh_entry**) for GC.  */
+
+static void 
+mark_func_eh_entry (arg)
+     void *arg;
+{
+  struct func_eh_entry *fee;
+  struct handler_info *h;
+  int i;
+
+  fee = *((struct func_eh_entry **) arg);
+
+  for (i = 0; i < current_func_eh_entry; ++i)
+    {
+      ggc_mark_rtx (fee->rethrow_label);
+      for (h = fee->handlers; h; h = h->next)
+       {
+         ggc_mark_rtx (h->handler_label);
+         if (h->type_info != CATCH_ALL_TYPE)
+           ggc_mark_tree ((tree) h->type_info);
+       }
+
+      /* Skip to the next entry in the array.  */
+      ++fee;
+    }
+}
+
 /* This group of functions initializes the exception handling data
    structures at the start of the compilation, initializes the data
    structures at the start of a function, and saves and restores the
@@ -2342,45 +2651,58 @@ init_eh ()
   first_rethrow_symbol = create_rethrow_ref (0);
   final_rethrow = gen_exception_label ();
   last_rethrow_symbol = create_rethrow_ref (CODE_LABEL_NUMBER (final_rethrow));
-}
 
+  ggc_add_rtx_root (&exception_handler_labels, 1);
+  ggc_add_rtx_root (&eh_return_context, 1);
+  ggc_add_rtx_root (&eh_return_stack_adjust, 1);
+  ggc_add_rtx_root (&eh_return_handler, 1);
+  ggc_add_rtx_root (&first_rethrow_symbol, 1);
+  ggc_add_rtx_root (&final_rethrow, 1);
+  ggc_add_rtx_root (&last_rethrow_symbol, 1);
+  ggc_add_root (&function_eh_regions, 1, sizeof (function_eh_regions),
+               mark_func_eh_entry);
+}
+  
 /* Initialize the per-function EH information.  */
 
 void
 init_eh_for_function ()
 {
-  current_function->eh = (struct eh_status *) xmalloc (sizeof (struct eh_status));
-
-  ehstack.top = 0;
-  catchstack.top = 0;
-  ehqueue.head = ehqueue.tail = 0;
-  catch_clauses = NULL_RTX;
-  false_label_stack = 0;
-  caught_return_label_stack = 0;
-  protect_list = NULL_TREE;
-  current_function_ehc = NULL_RTX;
+  cfun->eh = (struct eh_status *) xcalloc (1, sizeof (struct eh_status));
+  ehqueue = (struct eh_queue *) xcalloc (1, sizeof (struct eh_queue));
   eh_return_context = NULL_RTX;
   eh_return_stack_adjust = NULL_RTX;
   eh_return_handler = NULL_RTX;
-  eh_return_stub_label = NULL_RTX;
+}
+
+void
+free_eh_status (f)
+     struct function *f;
+{
+  free (f->eh->x_ehqueue);
+  free (f->eh);
+  f->eh = NULL;
 }
 \f
 /* This section is for the exception handling specific optimization
-   pass.  First are the internal routines, and then the main
-   optimization pass.  */
+   pass.  */
 
 /* Determine if the given INSN can throw an exception.  */
 
-static int
+int
 can_throw (insn)
      rtx insn;
 {
+  if (GET_CODE (insn) == INSN
+      && GET_CODE (PATTERN (insn)) == SEQUENCE)
+    insn = XVECEXP (PATTERN (insn), 0, 0);
+
   /* Calls can always potentially throw exceptions, unless they have
      a REG_EH_REGION note with a value of 0 or less.  */
   if (GET_CODE (insn) == CALL_INSN)
     {
       rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
-      if (!note || XINT (XEXP (note, 0), 0) > 0)
+      if (!note || INTVAL (XEXP (note, 0)) > 0)
        return 1;
     }
 
@@ -2395,6 +2717,27 @@ can_throw (insn)
   return 0;
 }
 
+/* Return nonzero if nothing in this function can throw.  */
+
+int
+nothrow_function_p ()
+{
+  rtx insn;
+
+  if (! flag_exceptions)
+    return 1;
+
+  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+    if (can_throw (insn))
+      return 0;
+  for (insn = current_function_epilogue_delay_list; insn;
+       insn = XEXP (insn, 1))
+    if (can_throw (insn))
+      return 0;
+
+  return 1;
+}
+
 /* Scan a exception region looking for the matching end and then
    remove it if possible. INSN is the start of the region, N is the
    region number, and DELETE_OUTER is to note if anything in this
@@ -2423,14 +2766,14 @@ scan_region (insn, n, delete_outer)
   /* Assume we can delete the region.  */
   int delete = 1;
 
-  /* Can't delete something which is rethrown to. */
+  /* Can't delete something which is rethrown from. */
   if (rethrow_used (n))
     delete = 0;
 
   if (insn == NULL_RTX
       || GET_CODE (insn) != NOTE
       || NOTE_LINE_NUMBER (insn) != NOTE_INSN_EH_REGION_BEG
-      || NOTE_BLOCK_NUMBER (insn) != n
+      || NOTE_EH_HANDLER (insn) != n
       || delete_outer == NULL)
     abort ();
 
@@ -2450,14 +2793,14 @@ scan_region (insn, n, delete_outer)
       if (GET_CODE (insn) == NOTE
          && NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG)
        {
-         insn = scan_region (insn, NOTE_BLOCK_NUMBER (insn), &delete);
+         insn = scan_region (insn, NOTE_EH_HANDLER (insn), &delete);
        }
 
       insn = NEXT_INSN (insn);
     }
 
   /* The _BEG/_END NOTEs must match and nest.  */
-  if (NOTE_BLOCK_NUMBER (insn) != n)
+  if (NOTE_EH_HANDLER (insn) != n)
     abort ();
 
   /* If anything in this exception region can throw, we can throw.  */
@@ -2535,14 +2878,15 @@ exception_optimize ()
             inbetween. We are also guaranteed that the value of insn
             returned will be valid, as otherwise scan_region won't
             return.  */
-         insn = scan_region (insn, NOTE_BLOCK_NUMBER (insn), &n);
+         insn = scan_region (insn, NOTE_EH_HANDLER (insn), &n);
        }
     }
 }
 
-/* This function determines whether any of the exception regions in the
-   current function are targets of a rethrow or not, and set the 
-   reference flag according.  */
+/* This function determines whether the rethrow labels for any of the
+   exception regions in the current function are used or not, and set
+   the reference flag according.  */
+
 void
 update_rethrow_references ()
 {
@@ -2553,13 +2897,11 @@ update_rethrow_references ()
   if (!flag_new_exceptions)
     return;
 
-  saw_region = (int *) alloca (current_func_eh_entry * sizeof (int));
-  saw_rethrow = (int *) alloca (current_func_eh_entry * sizeof (int));
-  bzero ((char *) saw_region, (current_func_eh_entry * sizeof (int)));
-  bzero ((char *) saw_rethrow, (current_func_eh_entry * sizeof (int)));
+  saw_region = (int *) xcalloc (current_func_eh_entry, sizeof (int));
+  saw_rethrow = (int *) xcalloc (current_func_eh_entry, sizeof (int));
 
   /* Determine what regions exist, and whether there are any rethrows
-     to those regions or not.  */
+     from those regions or not.  */
   for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
     if (GET_CODE (insn) == CALL_INSN)
       {
@@ -2576,7 +2918,7 @@ update_rethrow_references ()
         {
          if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG)
            {
-             region = find_func_region (NOTE_BLOCK_NUMBER (insn));
+             region = find_func_region (NOTE_EH_HANDLER (insn));
              saw_region[region] = 1;
            }
        }
@@ -2585,6 +2927,10 @@ update_rethrow_references ()
   for (x = 0; x < current_func_eh_entry; x++)
     if (saw_region[x])
       function_eh_regions[x].rethrow_ref = saw_rethrow[x];
+
+  /* Clean up.  */
+  free (saw_region);
+  free (saw_rethrow);
 }
 \f
 /* Various hooks for the DWARF 2 __throw routine.  */
@@ -2639,9 +2985,10 @@ expand_builtin_frob_return_addr (addr_tree)
    The first passes the exception context to the handler.  For this
    we use the return value register for a void*.
 
-   The second holds the stack pointer value to be restored.  For
-   this we use the static chain register if it exists and is different
-   from the previous, otherwise some arbitrary call-clobbered register.
+   The second holds the stack pointer value to be restored.  For this
+   we use the static chain register if it exists, is different from
+   the previous, and is call-clobbered; otherwise some arbitrary
+   call-clobbered register.
 
    The third holds the address of the handler itself.  Here we use
    some arbitrary call-clobbered register.  */
@@ -2649,10 +2996,10 @@ expand_builtin_frob_return_addr (addr_tree)
 static void
 eh_regs (pcontext, psp, pra, outgoing)
      rtx *pcontext, *psp, *pra;
-     int outgoing;
+     int outgoing ATTRIBUTE_UNUSED;
 {
   rtx rcontext, rsp, rra;
-  int i;
+  unsigned int i;
 
 #ifdef FUNCTION_OUTGOING_VALUE
   if (outgoing)
@@ -2668,7 +3015,8 @@ eh_regs (pcontext, psp, pra, outgoing)
     rsp = static_chain_incoming_rtx;
   else
     rsp = static_chain_rtx;
-  if (REGNO (rsp) == REGNO (rcontext))
+  if (REGNO (rsp) == REGNO (rcontext)
+      || ! call_used_regs [REGNO (rsp)])
 #endif /* STATIC_CHAIN_REGNUM */
     rsp = NULL_RTX;
 
@@ -2700,6 +3048,7 @@ eh_regs (pcontext, psp, pra, outgoing)
 /* Retrieve the register which contains the pointer to the eh_context
    structure set the __throw. */
 
+#if 0
 rtx 
 get_reg_for_handler ()
 {
@@ -2708,6 +3057,7 @@ get_reg_for_handler ()
                           current_function_decl);
   return reg1;
 }
+#endif
 
 /* Set up the epilogue with the magic bits we'll need to return to the
    exception handler.  */
@@ -2816,10 +3166,10 @@ set_insn_eh_region (first, region_num)
 
   for (insn = *first; insn; insn = NEXT_INSN (insn))
     {
-      if ((GET_CODE (insn) == NOTE) && 
-                        (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG))
+      if ((GET_CODE (insn) == NOTE)
+         && (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG))
         {
-          rnum = NOTE_BLOCK_NUMBER (insn);
+          rnum = NOTE_EH_HANDLER (insn);
           insn_eh_region[INSN_UID (insn)] =  rnum;
           insn = NEXT_INSN (insn);
           set_insn_eh_region (&insn, rnum);
@@ -2872,7 +3222,7 @@ init_insn_eh_region (first, max_uid)
         max_uid = INSN_UID (insn);
 
   maximum_uid = max_uid;
-  insn_eh_region = (int *) malloc ((max_uid + 1) * sizeof (int));
+  insn_eh_region = (int *) xmalloc ((max_uid + 1) * sizeof (int));
   insn = first;
   set_insn_eh_region (&insn, 0);
 }
@@ -2913,6 +3263,7 @@ in_same_eh_region (insn1, insn2)
    yet.  At some point in the future we can trim out handlers which we
    know cannot be called. (ie, if a block has an INT type handler,
    control will never be passed to an outer INT type handler).  */
+
 static void 
 process_nestinfo (block, info, nested_eh_region)
      int block;
@@ -2922,7 +3273,7 @@ process_nestinfo (block, info, nested_eh_region)
   handler_info *ptr, *last_ptr = NULL;
   int x, y, count = 0;
   int extra = 0;
-  handler_info **extra_handlers;
+  handler_info **extra_handlers = 0;
   int index = info->region_index[block];
 
   /* If we've already processed this block, simply return. */
@@ -2953,7 +3304,7 @@ process_nestinfo (block, info, nested_eh_region)
     extra = 0;
 
   info->num_handlers[index] = count + extra;
-  info->handlers[index] = (handler_info **) malloc ((count + extra) 
+  info->handlers[index] = (handler_info **) xmalloc ((count + extra) 
                                                    * sizeof (handler_info **));
 
   /* First put all our handlers into the list.  */
@@ -2991,6 +3342,7 @@ process_nestinfo (block, info, nested_eh_region)
 /* This function will allocate and initialize an eh_nesting_info structure. 
    It returns a pointer to the completed data structure.  If there are
    no exception regions, a NULL value is returned.  */
+
 eh_nesting_info *
 init_eh_nesting_info ()
 {
@@ -3001,12 +3353,12 @@ init_eh_nesting_info ()
   rtx insn;
   int x;
 
-  info = (eh_nesting_info *) malloc (sizeof (eh_nesting_info));
-  info->region_index = (int *) malloc ((max_label_num () + 1) * sizeof (int));
-  bzero ((char *) info->region_index, (max_label_num () + 1) * sizeof (int));
+  if (! flag_exceptions)
+    return 0;
 
-  nested_eh_region = (int *) alloca ((max_label_num () + 1) * sizeof (int));
-  bzero ((char *) nested_eh_region, (max_label_num () + 1) * sizeof (int));
+  info = (eh_nesting_info *) xmalloc (sizeof (eh_nesting_info));
+  info->region_index = (int *) xcalloc ((max_label_num () + 1), sizeof (int));
+  nested_eh_region = (int *) xcalloc (max_label_num () + 1, sizeof (int));
 
   /* Create the nested_eh_region list.  If indexed with a block number, it 
      returns the block number of the next outermost region, if any. 
@@ -3018,12 +3370,12 @@ init_eh_nesting_info ()
        {
           if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG)
             {
-             int block = NOTE_BLOCK_NUMBER (insn);
+             int block = NOTE_EH_HANDLER (insn);
              region_count++;
              info->region_index[block] = region_count;
               if (eh_note)
                 nested_eh_region [block] =
-                                     NOTE_BLOCK_NUMBER (XEXP (eh_note, 0));
+                                     NOTE_EH_HANDLER (XEXP (eh_note, 0));
               else
                 nested_eh_region [block] = 0;
               eh_note = gen_rtx_EXPR_LIST (VOIDmode, insn, eh_note);
@@ -3038,18 +3390,15 @@ init_eh_nesting_info ()
     {
       free (info->region_index);
       free (info);
+      free (nested_eh_region);
       return NULL;
     }
 
   region_count++;
-  info->handlers = (handler_info ***) malloc (region_count 
-                                             * sizeof (handler_info ***));
-  info->num_handlers = (int *) malloc (region_count * sizeof (int));
-  info->outer_index = (int *) malloc (region_count * sizeof (int));
-
-  bzero ((char *) info->handlers, region_count * sizeof (rtx *));
-  bzero ((char *) info->num_handlers, region_count * sizeof (int));
-  bzero ((char *) info->outer_index, region_count * sizeof (int));
+  info->handlers = (handler_info ***) xcalloc (region_count,
+                                              sizeof (handler_info ***));
+  info->num_handlers = (int *) xcalloc (region_count, sizeof (int));
+  info->outer_index = (int *) xcalloc (region_count, sizeof (int));
 
  /* Now initialize the handler lists for all exception blocks.  */
   for (x = 0; x <= max_label_num (); x++)
@@ -3058,6 +3407,10 @@ init_eh_nesting_info ()
        process_nestinfo (x, info, nested_eh_region);
     }
   info->region_count = region_count;
+
+  /* Clean up.  */
+  free (nested_eh_region);
+
   return info;
 }
 
@@ -3073,6 +3426,7 @@ init_eh_nesting_info ()
    HANDLERS is the address of a pointer to a vector of handler_info pointers.
    Upon return, this will have the handlers which can be reached by block.
    This function returns the number of elements in the handlers vector.  */
+
 int 
 reachable_handlers (block, info, insn, handlers)
      int block;
@@ -3091,7 +3445,7 @@ reachable_handlers (block, info, insn, handlers)
   if (insn && GET_CODE (insn) == CALL_INSN)
     {
       /* RETHROWs specify a region number from which we are going to rethrow.
-        This means we wont pass control to handlers in the specified
+        This means we won't pass control to handlers in the specified
         region, but rather any region OUTSIDE the specified region.
         We accomplish this by setting block to the outer_index of the
         specified region.  */
@@ -3111,7 +3465,7 @@ reachable_handlers (block, info, insn, handlers)
          note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
          if (note)
            {
-             int b = XINT (XEXP (note, 0), 0);
+             int b = INTVAL (XEXP (note, 0));
              if (b <= 0)
                index = 0;
              else
@@ -3150,5 +3504,6 @@ free_eh_nesting_info (info)
              free (info->handlers[x]);
          free (info->handlers);
        }
+      free (info);
     }
 }