]> gcc.gnu.org Git - gcc.git/blobdiff - gcc/except.c
except.c: Remove register_exception_table{,_p}.
[gcc.git] / gcc / except.c
index 91afbc3052b60e4c5e57e771c0b04f887d5026a2..c12185f04dd0fa63df1051b87b34b74310aad9bb 100644 (file)
@@ -1,5 +1,5 @@
 /* Implements exception handling.
-   Copyright (C) 1989, 92-95, 1996 Free Software Foundation, Inc.
+   Copyright (C) 1989, 92-96, 1997 Free Software Foundation, Inc.
    Contributed by Mike Stump <mrs@cygnus.com>.
 
 This file is part of GNU CC.
@@ -23,7 +23,7 @@ Boston, MA 02111-1307, USA.  */
 /* An exception is an event that can be signaled from within a
    function. This event can then be "caught" or "trapped" by the
    callers of this function. This potentially allows program flow to
-   be transferred to any arbitrary code assocated with a function call
+   be transferred to any arbitrary code associated with a function call
    several levels up the stack.
 
    The intended use for this mechanism is for signaling "exceptional
@@ -45,7 +45,7 @@ Boston, MA 02111-1307, USA.  */
 
    There are two major codegen options for exception handling.  The
    flag -fsjlj-exceptions can be used to select the setjmp/longjmp
-   approach, which is the default.  -fnosjlj-exceptions can be used to
+   approach, which is the default.  -fno-sjlj-exceptions can be used to
    get the PC range table approach.  While this is a compile time
    flag, an entire application must be compiled with the same codegen
    option.  The first is a PC range table approach, the second is a
@@ -71,7 +71,7 @@ Boston, MA 02111-1307, USA.  */
    perform tasks such as destruction of objects allocated on the
    stack.
 
-   In the current implementaion, cleanups are handled by allocating an
+   In the current implementation, cleanups are handled by allocating an
    exception region for the area that the cleanup is designated for,
    and the handler for the region performs the cleanup and then
    rethrows the exception to the outer exception region. From the
@@ -87,34 +87,47 @@ Boston, MA 02111-1307, USA.  */
    exception region, and the address of the handler designated for
    that region.
 
-   At program startup each object file invokes a function named
+   If the target does not use the DWARF 2 frame unwind information, at
+   program startup each object file invokes a function named
    __register_exceptions with the address of its local
-   __EXCEPTION_TABLE__. __register_exceptions is defined in libgcc2.c,
-   and is responsible for recording all of the exception regions into
-   one list (which is kept in a static variable named exception_table_list).
+   __EXCEPTION_TABLE__. __register_exceptions is defined in libgcc2.c, and
+   is responsible for recording all of the exception regions into one list
+   (which is kept in a static variable named exception_table_list).
+
+   On targets that support crtstuff.c, the unwind information
+   is stored in a section named .eh_frame and the information for the
+   entire shared object or program is registered with a call to
+   __register_frame_info.  On other targets, the information for each
+   translation unit is registered from the file generated by collect2.
+   __register_frame_info is defined in frame.c, and is responsible for
+   recording all of the unwind regions into one list (which is kept in a
+   static variable named unwind_table_list).
 
    The function __throw is actually responsible for doing the
-   throw. In the C++ frontend, __throw is generated on a
+   throw. On machines that have unwind info support, __throw is generated
+   by code in libgcc2.c, otherwise __throw is generated on a
    per-object-file basis for each source file compiled with
-   -fexceptions. Before __throw is invoked, the current context
-   of the throw needs to be placed in the global variable __eh_pc.
+   -fexceptions by the the C++ frontend.  Before __throw is invoked,
+   the current context of the throw needs to be placed in the global
+   variable __eh_pc.
 
    __throw attempts to find the appropriate exception handler for the 
    PC value stored in __eh_pc by calling __find_first_exception_table_match
    (which is defined in libgcc2.c). If __find_first_exception_table_match
-   finds a relevant handler, __throw jumps directly to it.
-
-   If a handler for the context being thrown from can't be found,
-   __throw is responsible for unwinding the stack, determining the
-   address of the caller of the current function (which will be used
-   as the new context to throw from), and then restarting the process
-   of searching for a handler for the new context. __throw may also
-   call abort if it is unable to unwind the stack, and can also
-   call an external library function named __terminate if it reaches
-   the top of the stack without finding an appropriate handler. (By
-   default __terminate invokes abort, but this behavior can be
-   changed by the user to perform some sort of cleanup behavior before
-   exiting).
+   finds a relevant handler, __throw transfers control directly to it.
+
+   If a handler for the context being thrown from can't be found, __throw
+   walks (see Walking the stack below) the stack up the dynamic call chain to
+   continue searching for an appropriate exception handler based upon the
+   caller of the function it last sought a exception handler for.  It stops
+   then either an exception handler is found, or when the top of the
+   call chain is reached.
+
+   If no handler is found, an external library function named
+   __terminate is called.  If a handler is found, then we restart
+   our search for a handler at the end of the call chain, and repeat
+   the search process, but instead of just walking up the call chain,
+   we unwind the call chain as we walk up it.
 
    Internal implementation details:
 
@@ -231,40 +244,79 @@ Boston, MA 02111-1307, USA.  */
    incorrect results is better than halting the program.
 
 
-   Unwinding the stack:
+   Walking the stack:
 
-   The details of unwinding the stack to the next frame can be rather
-   complex. While in many cases a generic __unwind_function routine
-   can be used by the generated exception handling code to do this, it
-   is often necessary to generate inline code to do the unwinding.
+   The stack is walked by starting with a pointer to the current
+   frame, and finding the pointer to the callers frame.  The unwind info
+   tells __throw how to find it.
 
-   Whether or not these inlined unwinders are necessary is
-   target-specific.
+   Unwinding the stack:
 
-   By default, if the target-specific backend doesn't supply a
-   definition for __unwind_function, inlined unwinders will be used
-   instead. The main tradeoff here is in text space utilization.
-   Obviously, if inline unwinders have to be generated repeatedly,
-   this uses much more space than if a single routine is used.
+   When we use the term unwinding the stack, we mean undoing the
+   effects of the function prologue in a controlled fashion so that we
+   still have the flow of control.  Otherwise, we could just return
+   (jump to the normal end of function epilogue).
+
+   This is done in __throw in libgcc2.c when we know that a handler exists
+   in a frame higher up the call stack than its immediate caller.
+
+   To unwind, we find the unwind data associated with the frame, if any.
+   If we don't find any, we call the library routine __terminate.  If we do
+   find it, we use the information to copy the saved register values from
+   that frame into the register save area in the frame for __throw, return
+   into a stub which updates the stack pointer, and jump to the handler.
+   The normal function epilogue for __throw handles restoring the saved
+   values into registers.
+
+   When unwinding, we use this method if we know it will
+   work (if DWARF2_UNWIND_INFO is defined).  Otherwise, we know that
+   an inline unwinder will have been emitted for any function that
+   __unwind_function cannot unwind.  The inline unwinder appears as a
+   normal exception handler for the entire function, for any function
+   that we know cannot be unwound by __unwind_function.  We inform the
+   compiler of whether a function can be unwound with
+   __unwind_function by having DOESNT_NEED_UNWINDER evaluate to true
+   when the unwinder isn't needed.  __unwind_function is used as an
+   action of last resort.  If no other method can be used for
+   unwinding, __unwind_function is used.  If it cannot unwind, it
+   should call __terminate.
+
+   By default, if the target-specific backend doesn't supply a definition
+   for __unwind_function and doesn't support DWARF2_UNWIND_INFO, inlined
+   unwinders will be used instead. The main tradeoff here is in text space
+   utilization.  Obviously, if inline unwinders have to be generated
+   repeatedly, this uses much more space than if a single routine is used.
 
    However, it is simply not possible on some platforms to write a
    generalized routine for doing stack unwinding without having some
-   form of additional data associated with each function. The current
-   implementation encodes this data in the form of additional machine
-   instructions. This is clearly not desirable, as it is extremely
-   inefficient. The next implementation will provide a set of metadata
-   for each function that will provide the needed information.
+   form of additional data associated with each function.  The current
+   implementation can encode this data in the form of additional
+   machine instructions or as static data in tabular form.  The later
+   is called the unwind data.
 
-   The backend macro DOESNT_NEED_UNWINDER is used to conditionalize
-   whether or not per-function unwinders are needed. If DOESNT_NEED_UNWINDER
-   is defined and has a non-zero value, a per-function unwinder is
-   not emitted for the current function.
+   The backend macro DOESNT_NEED_UNWINDER is used to conditionalize whether
+   or not per-function unwinders are needed. If DOESNT_NEED_UNWINDER is
+   defined and has a non-zero value, a per-function unwinder is not emitted
+   for the current function.  If the static unwind data is supported, then
+   a per-function unwinder is not emitted.
 
    On some platforms it is possible that neither __unwind_function
    nor inlined unwinders are available. For these platforms it is not
    possible to throw through a function call, and abort will be
    invoked instead of performing the throw. 
 
+   The reason the unwind data may be needed is that on some platforms
+   the order and types of data stored on the stack can vary depending
+   on the type of function, its arguments and returned values, and the
+   compilation options used (optimization versus non-optimization,
+   -fomit-frame-pointer, processor variations, etc).
+
+   Unfortunately, this also means that throwing through functions that
+   aren't compiled with exception handling support will still not be
+   possible on some platforms. This problem is currently being
+   investigated, but no solutions have been found that do not imply
+   some unacceptable performance penalties.
+
    Future directions:
 
    Currently __throw makes no differentiation between cleanups and
@@ -309,28 +361,11 @@ Boston, MA 02111-1307, USA.  */
    query various state variables to determine what actions are to be
    performed next.
 
-   Another major problem that is being worked on is the issue with
-   stack unwinding on various platforms. Currently the only platform
-   that has support for __unwind_function is the Sparc; all other
-   ports require per-function unwinders, which causes large amounts of
-   code bloat.
-
-   Ideally it would be possible to store a small set of metadata with
-   each function that would then make it possible to write a
-   __unwind_function for every platform. This would eliminate the
-   need for per-function unwinders.
-
-   The main reason the data is needed is that on some platforms the
-   order and types of data stored on the stack can vary depending on
-   the type of function, its arguments and returned values, and the
-   compilation options used (optimization versus non-optimization,
-   -fomit-frame-pointer, processor variations, etc).
-
-   Unfortunately, this also means that throwing through functions that
-   aren't compiled with exception handling support will still not be
-   possible on some platforms. This problem is currently being
-   investigated, but no solutions have been found that do not imply
-   some unacceptable performance penalties.
+   Another major problem that is being worked on is the issue with stack
+   unwinding on various platforms. Currently the only platforms that have
+   support for the generation of a generic unwinder are the SPARC and MIPS.
+   All other ports require per-function unwinders, which produce large
+   amounts of code bloat.
 
    For setjmp/longjmp based exception handling, some of the details
    are as above, but there are some additional details.  This section
@@ -342,7 +377,7 @@ Boston, MA 02111-1307, USA.  */
    for all the machine specific details.  There is no variable context
    of a throw, just the one implied by the dynamic handler stack
    pointed to by the dynamic handler chain.  There is no exception
-   table, and no calls to __register_excetpions.  __sjthrow is used
+   table, and no calls to __register_exceptions.  __sjthrow is used
    instead of __throw, and it works by using the dynamic handler
    chain, and longjmp.  -fasynchronous-exceptions has no effect, as
    the elimination of trivial exception regions is not yet performed.
@@ -354,6 +389,7 @@ Boston, MA 02111-1307, USA.  */
 
 
 #include "config.h"
+#include "defaults.h"
 #include <stdio.h>
 #include "rtl.h"
 #include "tree.h"
@@ -368,12 +404,11 @@ Boston, MA 02111-1307, USA.  */
 #include "insn-config.h"
 #include "recog.h"
 #include "output.h"
-#include "assert.h"
 
 /* One to use setjmp/longjmp method of generating code for exception
    handling.  */
 
-int exceptions_via_longjmp = 1;
+int exceptions_via_longjmp = 2;
 
 /* One to enable asynchronous exception support.  */
 
@@ -382,7 +417,7 @@ int asynchronous_exceptions = 0;
 /* One to protect cleanup actions with a handler that calls
    __terminate, zero otherwise.  */
 
-int protect_cleanup_actions_with_terminate = 0;
+int protect_cleanup_actions_with_terminate;
 
 /* A list of labels used for exception handlers.  Created by
    find_exception_handler_labels for the optimization passes.  */
@@ -396,19 +431,12 @@ rtx exception_handler_labels;
 
 int throw_used;
 
-/* The dynamic handler chain.  Nonzero if the function has already
-   fetched a pointer to the dynamic handler chain for exception
-   handling.  */
-
-rtx current_function_dhc;
-
-/* The dynamic cleanup chain.  Nonzero if the function has already
-   fetched a pointer to the dynamic cleanup chain for exception
-   handling.  */
+/* The EH context.  Nonzero if the function has already
+   fetched a pointer to the EH context  for exception handling.  */
 
-rtx current_function_dcc;
+rtx current_function_ehc;
 
-/* A stack used for keeping track of the currectly active exception
+/* A stack used for keeping track of the currently active exception
    handling region.  As each exception region is started, an entry
    describing the region is pushed onto this stack.  The current
    region can be found by looking at the top of the stack, and as we
@@ -448,22 +476,22 @@ static tree protect_list;
 
 /* Keeps track of the label to resume to should one want to resume
    normal control flow out of a handler (instead of, say, returning to
-   the caller of the current function or exiting the program).  Also
-   used as the context of a throw to rethrow an exception to the outer
-   exception region.  */
+   the caller of the current function or exiting the program).  */
 
 struct label_node *caught_return_label_stack = NULL;
 
-/* A random data area for the front end's own use.  */
+/* Keeps track of the label used as the context of a throw to rethrow an
+   exception to the outer exception region.  */
 
-struct label_node *false_label_stack = NULL;
+struct label_node *outer_context_label_stack = NULL;
 
-/* The rtx and the tree for the saved PC value.  */
+/* A random data area for the front end's own use.  */
 
-rtx eh_saved_pc_rtx;
-tree eh_saved_pc;
+struct label_node *false_label_stack = NULL;
 
 rtx expand_builtin_return_addr PROTO((enum built_in_function, int, rtx));
+static void expand_rethrow     PROTO((rtx));
+
 \f
 /* Various support routines to manipulate the various data structures
    used by the exception handling code.  */
@@ -533,26 +561,22 @@ copy_eh_entry (entry)
   return newentry;
 }
 
-/* Push a new eh_node entry onto STACK, and return the start label for
-   the entry.  */
+/* Push a new eh_node entry onto STACK.  */
 
-static rtx
+static void
 push_eh_entry (stack)
      struct eh_stack *stack;
 {
   struct eh_node *node = (struct eh_node *) xmalloc (sizeof (struct eh_node));
   struct eh_entry *entry = (struct eh_entry *) xmalloc (sizeof (struct eh_entry));
 
-  entry->start_label = gen_label_rtx ();
-  entry->end_label = gen_label_rtx ();
+  entry->outer_context = gen_label_rtx ();
   entry->exception_handler_label = gen_label_rtx ();
   entry->finalization = NULL_TREE;
 
   node->entry = entry;
   node->chain = stack->top;
   stack->top = node;
-
-  return entry->start_label;
 }
 
 /* Pop an entry from the given STACK.  */
@@ -649,17 +673,12 @@ eh_outer_context (addr)
 {
   /* First mask out any unwanted bits.  */
 #ifdef MASK_RETURN_ADDR
-  emit_insn (gen_rtx (SET, Pmode,
-                     addr,
-                     gen_rtx (AND, Pmode,
-                              addr, MASK_RETURN_ADDR)));
+  expand_and (addr, MASK_RETURN_ADDR, addr);
 #endif
 
-  /* Then subtract out enough to get into the appropriate region.  If
-     this is defined, assume we don't need to subtract anything as it
-     is already within the correct region.  */
-#if ! defined (RETURN_ADDR_OFFSET)
-  addr = plus_constant (addr, -1);
+  /* Then adjust to find the real return address.  */
+#if defined (RETURN_ADDR_OFFSET)
+  addr = plus_constant (addr, RETURN_ADDR_OFFSET);
 #endif
 
   return addr;
@@ -688,6 +707,70 @@ add_partial_entry (handler)
   pop_obstacks ();
 }
 
+/* Emit code to get EH context to current function.  */
+
+static rtx
+call_get_eh_context ()
+{
+  static tree fn;
+  tree expr;
+
+  if (fn == NULL_TREE)
+    {
+      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);
+      fn = build_decl (FUNCTION_DECL, fn, fntype);
+      DECL_EXTERNAL (fn) = 1;
+      TREE_PUBLIC (fn) = 1;
+      DECL_ARTIFICIAL (fn) = 1;
+      TREE_READONLY (fn) = 1;
+      make_decl_rtl (fn, NULL_PTR, 1);
+      assemble_external (fn);
+      pop_obstacks ();
+    }
+
+  expr = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (fn)), fn);
+  expr = build (CALL_EXPR, TREE_TYPE (TREE_TYPE (fn)),
+               expr, NULL_TREE, NULL_TREE);
+  TREE_SIDE_EFFECTS (expr) = 1;
+
+  return copy_to_reg (expand_expr (expr, NULL_RTX, VOIDmode, 0));
+}
+
+/* Get a reference to the EH context.
+   We will only generate a register for the current function EH context here,
+   and emit a USE insn to mark that this is a EH context register.
+
+   Later, emit_eh_context will emit needed call to __get_eh_context
+   in libgcc2, and copy the value to the register we have generated. */
+
+rtx
+get_eh_context ()
+{
+  if (current_function_ehc == 0)
+    {
+      rtx insn;
+
+      current_function_ehc = gen_reg_rtx (Pmode);
+      
+      insn = gen_rtx (USE,
+                     GET_MODE (current_function_ehc),
+                     current_function_ehc);
+      insn = emit_insn_before (insn, get_first_nonparm_insn ());
+
+      REG_NOTES (insn)
+       = gen_rtx (EXPR_LIST, 
+                  REG_EH_CONTEXT, current_function_ehc,
+                  REG_NOTES (insn));
+    }
+  return current_function_ehc;
+}
+     
 /* Get a reference to the dynamic handler chain.  It points to the
    pointer to the next element in the dynamic handler chain.  It ends
    when there are no more elements in the dynamic handler chain, when
@@ -695,43 +778,20 @@ add_partial_entry (handler)
    pointer, is an area suitable for setjmp/longjmp when
    DONT_USE_BUILTIN_SETJMP is defined, and an area suitable for
    __builtin_setjmp/__builtin_longjmp when DONT_USE_BUILTIN_SETJMP
-   isn't defined.
-
-   This routine is here to facilitate the porting of this code to
-   systems with threads.  One can either replace the routine we emit a
-   call for here in libgcc2.c, or one can modify this routine to work
-   with their thread system.  */
+   isn't defined. */
 
 rtx
 get_dynamic_handler_chain ()
 {
-#if 0
-  /* Do this once we figure out how to get this to the front of the
-     function, and we really only want one per real function, not one
-     per inlined function.  */
-  if (current_function_dhc == 0)
-    {
-      rtx dhc, insns;
-      start_sequence ();
-
-      dhc = emit_library_call_value (get_dynamic_handler_chain_libfunc,
-                                    NULL_RTX, 1,
-                                    Pmode, 0);
-      current_function_dhc = copy_to_reg (dhc);
-      insns = get_insns ();
-      end_sequence ();
-      emit_insns_before (insns, get_first_nonparm_insn ());
-    }
-#else
-  rtx dhc;
-  dhc = emit_library_call_value (get_dynamic_handler_chain_libfunc,
-                                NULL_RTX, 1,
-                                Pmode, 0);
-  current_function_dhc = copy_to_reg (dhc);
-#endif
+  rtx ehc, dhc, result;
+
+  ehc = get_eh_context ();
+  dhc = ehc;
 
-  /* We don't want a copy of the dhc, but rather, the single dhc.  */
-  return gen_rtx (MEM, Pmode, current_function_dhc);
+  result = copy_to_reg (dhc);
+
+  /* We don't want a copy of the dcc, but rather, the single dcc.  */
+  return gen_rtx (MEM, Pmode, result);
 }
 
 /* Get a reference to the dynamic cleanup chain.  It points to the
@@ -743,15 +803,15 @@ get_dynamic_handler_chain ()
 rtx
 get_dynamic_cleanup_chain ()
 {
-  rtx dhc, dcc;
+  rtx dhc, dcc, result;
 
   dhc = get_dynamic_handler_chain ();
   dcc = plus_constant (dhc, GET_MODE_SIZE (Pmode));
 
-  current_function_dcc = copy_to_reg (dcc);
+  result = copy_to_reg (dcc);
 
   /* We don't want a copy of the dcc, but rather, the single dcc.  */
-  return gen_rtx (MEM, Pmode, current_function_dcc);
+  return gen_rtx (MEM, Pmode, result);
 }
 
 /* Generate code to evaluate X and jump to LABEL if the value is nonzero.
@@ -964,6 +1024,7 @@ expand_eh_region_start_tree (decl, cleanup)
     }
 
   expand_eh_region_start_for_decl (decl);
+  ehstack.top->entry->finalization = cleanup;
 
   return 0;
 }
@@ -1005,12 +1066,10 @@ expand_eh_region_start_for_decl (decl)
       expand_dhc_cleanup (decl);
     }
 
-  if (exceptions_via_longjmp == 0)
-    note = emit_note (NULL_PTR, NOTE_INSN_EH_REGION_BEG);
-  emit_label (push_eh_entry (&ehstack));
-  if (exceptions_via_longjmp == 0)
-    NOTE_BLOCK_NUMBER (note)
-      = CODE_LABEL_NUMBER (ehstack.top->entry->exception_handler_label);
+  push_eh_entry (&ehstack);
+  note = emit_note (NULL_PTR, NOTE_INSN_EH_REGION_BEG);
+  NOTE_BLOCK_NUMBER (note)
+    = CODE_LABEL_NUMBER (ehstack.top->entry->exception_handler_label);
   if (exceptions_via_longjmp)
     start_dynamic_handler ();
 }
@@ -1039,29 +1098,31 @@ expand_eh_region_end (handler)
      tree handler;
 {
   struct eh_entry *entry;
+  rtx note;
 
   if (! doing_eh (0))
     return;
 
   entry = pop_eh_entry (&ehstack);
 
-  if (exceptions_via_longjmp == 0)
+  note = emit_note (NULL_PTR, NOTE_INSN_EH_REGION_END);
+  NOTE_BLOCK_NUMBER (note)
+    = CODE_LABEL_NUMBER (entry->exception_handler_label);
+  if (exceptions_via_longjmp == 0
+      /* We share outer_context between regions; only emit it once.  */
+      && INSN_UID (entry->outer_context) == 0)
     {
-      rtx note = emit_note (NULL_PTR, NOTE_INSN_EH_REGION_END);
-      NOTE_BLOCK_NUMBER (note) = CODE_LABEL_NUMBER (entry->exception_handler_label);
-    }
+      rtx label;
 
-  /* Emit a label marking the end of this exception region.  */
-  emit_label (entry->end_label);
+      label = gen_label_rtx ();
+      emit_jump (label);
 
-  if (exceptions_via_longjmp == 0)
-    {
-      /* Put in something that takes up space, as otherwise the end
-        address for this EH region could have the exact same address as
-        its outer region. This would cause us to miss the fact that
-        resuming exception handling with this PC value would be inside
-        the outer region.  */
-      emit_insn (gen_nop ());
+      /* Emit a label marking the end of this exception region that
+        is used for rethrowing into the outer context.  */
+      emit_label (entry->outer_context);
+      expand_internal_throw ();
+
+      emit_label (label);
     }
 
   entry->finalization = handler;
@@ -1085,6 +1146,45 @@ expand_eh_region_end (handler)
     }
 }
 
+/* End the EH region for a goto fixup.  We only need them in the region-based
+   EH scheme.  */
+
+void
+expand_fixup_region_start ()
+{
+  if (! doing_eh (0) || exceptions_via_longjmp)
+    return;
+
+  expand_eh_region_start ();
+}
+
+/* End the EH region for a goto fixup.  CLEANUP is the cleanup we just
+   expanded; to avoid running it twice if it throws, we look through the
+   ehqueue for a matching region and rethrow from its outer_context.  */
+
+void
+expand_fixup_region_end (cleanup)
+     tree cleanup;
+{
+  struct eh_node *node;
+
+  if (! doing_eh (0) || exceptions_via_longjmp)
+    return;
+
+  for (node = ehstack.top; node && node->entry->finalization != cleanup; )
+    node = node->chain;
+  if (node == 0)
+    for (node = ehqueue.head; node && node->entry->finalization != cleanup; )
+      node = node->chain;
+  if (node == 0)
+    abort ();
+
+  ehstack.top->entry->outer_context = node->entry->outer_context;
+
+  /* Just rethrow.  size_zero_node is just a NOP.  */
+  expand_eh_region_end (size_zero_node);
+}
+
 /* If we are using the setjmp/longjmp EH codegen method, we emit a
    call to __sjthrow.
 
@@ -1109,7 +1209,6 @@ emit_throw ()
 #ifdef JUMP_TO_THROW
       emit_indirect_jump (throw_libfunc);
 #else
-      SYMBOL_REF_USED (throw_libfunc) = 1;
       emit_library_call (throw_libfunc, 0, VOIDmode, 0);
 #endif
       throw_used = 1;
@@ -1117,27 +1216,13 @@ emit_throw ()
   emit_barrier ();
 }
 
-/* An internal throw with an indirect CONTEXT we want to throw from.
-   CONTEXT evaluates to the context of the throw.  */
-
-static void
-expand_internal_throw_indirect (context)
-     rtx context;
-{
-  assemble_external (eh_saved_pc);
-  emit_move_insn (eh_saved_pc_rtx, context);
-  emit_throw ();
-}
-
-/* An internal throw with a direct CONTEXT we want to throw from.
-   CONTEXT must be a label; its address will be used as the context of
-   the throw.  */
+/* Throw the current exception.  If appropriate, this is done by jumping
+   to the next handler.  */
 
 void
-expand_internal_throw (context)
-     rtx context;
+expand_internal_throw ()
 {
-  expand_internal_throw_indirect (gen_rtx (LABEL_REF, Pmode, context));
+  emit_throw ();
 }
 
 /* Called from expand_exception_blocks and expand_end_catch_block to
@@ -1159,24 +1244,28 @@ expand_leftover_cleanups ()
       /* Output the label for the start of the exception handler.  */
       emit_label (entry->exception_handler_label);
 
+#ifdef HAVE_exception_receiver
+      if (! exceptions_via_longjmp)
+       if (HAVE_exception_receiver)
+         emit_insn (gen_exception_receiver ());
+#endif
+
+#ifdef HAVE_nonlocal_goto_receiver
+      if (! exceptions_via_longjmp)
+       if (HAVE_nonlocal_goto_receiver)
+         emit_insn (gen_nonlocal_goto_receiver ());
+#endif
+
       /* 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)
-       {
-         if (exceptions_via_longjmp)
-           emit_throw ();
-         else
-           {
-             /* The below can be optimized away, and we could just fall into the
-                next EH handler, if we are certain they are nested.  */
-             /* Emit code to throw to the outer context if we fall off
-                the end of the handler.  */
-             expand_internal_throw (entry->end_label);
-           }
-       }
+       /* 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);
     }
 }
@@ -1203,10 +1292,13 @@ expand_start_all_catch ()
 {
   struct eh_entry *entry;
   tree label;
+  rtx outer_context;
 
   if (! doing_eh (1))
     return;
 
+  outer_context = ehstack.top->entry->outer_context;
+
   /* End the try block.  */
   expand_eh_region_end (integer_zero_node);
 
@@ -1214,19 +1306,9 @@ expand_start_all_catch ()
   label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
 
   /* The label for the exception handling block that we will save.
-     This is Lresume in the documention.  */
+     This is Lresume in the documentation.  */
   expand_label (label);
   
-  if (exceptions_via_longjmp == 0)
-    {
-      /* Put in something that takes up space, as otherwise the end
-        address for the EH region could have the exact same address as
-        the outer region, causing us to miss the fact that resuming
-        exception handling with this PC value would be inside the outer
-        region.  */
-      emit_insn (gen_nop ());
-    }
-
   /* Push the label that points to where normal flow is resumed onto
      the top of the label stack.  */
   push_label_entry (&caught_return_label_stack, NULL_RTX, label);
@@ -1252,6 +1334,18 @@ expand_start_all_catch ()
         end up being the handler.  */
       emit_label (entry->exception_handler_label);
 
+#ifdef HAVE_exception_receiver
+      if (! exceptions_via_longjmp)
+       if (HAVE_exception_receiver)
+         emit_insn (gen_exception_receiver ());
+#endif
+
+#ifdef HAVE_nonlocal_goto_receiver
+      if (! exceptions_via_longjmp)
+       if (HAVE_nonlocal_goto_receiver)
+         emit_insn (gen_nonlocal_goto_receiver ());
+#endif
+
       /* When we get down to the matching entry for this try block, stop.  */
       if (entry->finalization == integer_zero_node)
        {
@@ -1265,24 +1359,24 @@ expand_start_all_catch ()
 
       prev = get_last_insn ();
       if (prev == NULL || GET_CODE (prev) != BARRIER)
-       {
-         if (exceptions_via_longjmp)
-           emit_throw ();
-         else
-           {
-             /* 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.
+       /* 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);
 
-                The below can be optimized away (and we could just fall
-                into the next EH handler) if we are certain they are
-                nested.  */
-
-             expand_internal_throw (entry->end_label);
-           }
-       }
+      do_pending_stack_adjust ();
       free (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
+     do this because we are not physically within the region, if any, that
+     logically contains this catch block.  */
+  if (! exceptions_via_longjmp)
+    {
+      expand_eh_region_start ();
+      ehstack.top->entry->outer_context = outer_context;
+    }
 }
 
 /* Finish up the catch block.  At this point all the insns for the
@@ -1294,28 +1388,30 @@ expand_start_all_catch ()
 void
 expand_end_all_catch ()
 {
-  rtx new_catch_clause;
+  rtx new_catch_clause, outer_context = NULL_RTX;
 
   if (! doing_eh (1))
     return;
 
-  if (exceptions_via_longjmp)
-    emit_throw ();
-  else
+  if (! exceptions_via_longjmp)
     {
-      /* Code to throw out to outer context, if we fall off end of catch
-        handlers.  This is rethrow (Lresume, same id, same obj) in the
-        documentation. We use Lresume because we know that it will throw
-        to the correct context.
+      outer_context = ehstack.top->entry->outer_context;
 
-        In other words, if the catch handler doesn't exit or return, we
-        do a "throw" (using the address of Lresume as the point being
-        thrown from) so that the outer EH region can then try to process
-        the exception.  */
-
-      expand_internal_throw (DECL_RTL (top_label_entry (&caught_return_label_stack)));
+      /* Finish the rethrow region.  size_zero_node is just a NOP.  */
+      expand_eh_region_end (size_zero_node);
     }
 
+  /* Code to throw out to outer context, if we fall off end of catch
+     handlers.  This is rethrow (Lresume, same id, same obj) in the
+     documentation. We use Lresume because we know that it will throw
+     to the correct context.
+
+     In other words, if the catch handler doesn't exit or return, we
+     do a "throw" (using the address of Lresume as the point being
+     thrown from) so that the outer EH region can then try to process
+     the exception.  */
+  expand_rethrow (outer_context);
+
   /* Now we have the complete catch sequence.  */
   new_catch_clause = get_insns ();
   end_sequence ();
@@ -1323,6 +1419,7 @@ expand_end_all_catch ()
   /* This level of catch blocks is done, so set up the successful
      catch jump label for the next layer of catch blocks.  */
   pop_label_entry (&caught_return_label_stack);
+  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);
@@ -1333,6 +1430,18 @@ expand_end_all_catch ()
   /* Here we fall through into the continuation code.  */
 }
 
+/* Rethrow from the outer context LABEL.  */
+
+static void
+expand_rethrow (label)
+     rtx label;
+{
+  if (exceptions_via_longjmp)
+    emit_throw ();
+  else
+    emit_jump (label);
+}
+
 /* End all the pending exception regions on protect_list. The handlers
    will be emitted when expand_leftover_cleanups is invoked.  */
 
@@ -1423,10 +1532,8 @@ add_eh_table_entry (n)
          if (eh_table_max_size < 0)
            abort ();
 
-         if ((eh_table = (int *) realloc (eh_table,
-                                          eh_table_max_size * sizeof (int)))
-             == 0)
-           fatal ("virtual memory exhausted");
+         eh_table = (int *) xrealloc (eh_table,
+                                      eh_table_max_size * sizeof (int));
        }
       else
        {
@@ -1489,7 +1596,7 @@ output_exception_table ()
   int i;
   extern FILE *asm_out_file;
 
-  if (! doing_eh (0))
+  if (! doing_eh (0) || ! eh_table)
     return;
 
   exception_section ();
@@ -1498,200 +1605,60 @@ output_exception_table ()
   assemble_align (GET_MODE_ALIGNMENT (ptr_mode));
   assemble_label ("__EXCEPTION_TABLE__");
 
-  assemble_integer (const0_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
-  assemble_integer (const0_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
-  assemble_integer (const0_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
-  putc ('\n', asm_out_file);           /* blank line */
-
   for (i = 0; i < eh_table_size; ++i)
     output_exception_table_entry (asm_out_file, eh_table[i]);
 
   free (eh_table);
 
   /* Ending marker for table.  */
-  assemble_label ("__EXCEPTION_END__");
   assemble_integer (constm1_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
   assemble_integer (constm1_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
   assemble_integer (constm1_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
   putc ('\n', asm_out_file);           /* blank line */
 }
-
-/* Generate code to initialize the exception table at program startup
-   time.  */
-
-void
-register_exception_table ()
-{
-  emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "__register_exceptions"), 0,
-                    VOIDmode, 1,
-                    gen_rtx (SYMBOL_REF, Pmode, "__EXCEPTION_TABLE__"),
-                    Pmode);
-}
 \f
-/* Emit the RTL for the start of the per-function unwinder for the
-   current function. See emit_unwinder for further information.
-
-   DOESNT_NEED_UNWINDER is a target-specific macro that determines if
-   the current function actually needs a per-function unwinder or not.
-   By default, all functions need one.  */
-
-void
-start_eh_unwinder ()
-{
-#ifdef DOESNT_NEED_UNWINDER
-  if (DOESNT_NEED_UNWINDER)
-    return;
-#endif
-
-  /* If we are using the setjmp/longjmp implementation, we don't need a
-     per function unwinder.  */
-
-  if (exceptions_via_longjmp)
-    return;
-
-  expand_eh_region_start ();
-}
+/* Emit code to get EH context.
+   
+   We have to scan thru the code to find possible EH context registers.
+   Inlined functions may use it too, and thus we'll have to be able
+   to change them too.
 
-/* Emit insns for the end of the per-function unwinder for the
-   current function.  */
+   This is done only if using exceptions_via_longjmp. */
 
 void
-end_eh_unwinder ()
+emit_eh_context ()
 {
-  tree expr;
-  rtx return_val_rtx, ret_val, label, end, insns;
+  rtx insn;
+  rtx ehc = 0;
 
   if (! doing_eh (0))
     return;
 
-#ifdef DOESNT_NEED_UNWINDER
-  if (DOESNT_NEED_UNWINDER)
-    return;
-#endif
-
-  /* If we are using the setjmp/longjmp implementation, we don't need a
-     per function unwinder.  */
-
-  if (exceptions_via_longjmp)
-    return;
-
-  assemble_external (eh_saved_pc);
-
-  expr = make_node (RTL_EXPR);
-  TREE_TYPE (expr) = void_type_node;
-  RTL_EXPR_RTL (expr) = const0_rtx;
-  TREE_SIDE_EFFECTS (expr) = 1;
-  start_sequence_for_rtl_expr (expr);
-
-  /* ret_val will contain the address of the code where the call
-     to the current function occurred.  */
-  ret_val = expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS,
-                                       0, hard_frame_pointer_rtx);
-  return_val_rtx = copy_to_reg (ret_val);
-
-  /* Get the address we need to use to determine what exception
-     handler should be invoked, and store it in __eh_pc.  */
-  return_val_rtx = eh_outer_context (return_val_rtx);
-  emit_move_insn (eh_saved_pc_rtx, return_val_rtx);
-  
-  /* Either set things up so we do a return directly to __throw, or
-     we return here instead.  */
-#ifdef JUMP_TO_THROW
-  emit_move_insn (ret_val, throw_libfunc);
-#else
-  label = gen_label_rtx ();
-  emit_move_insn (ret_val, gen_rtx (LABEL_REF, Pmode, label));
-#endif
-
-#ifdef RETURN_ADDR_OFFSET
-  return_val_rtx = plus_constant (ret_val, -RETURN_ADDR_OFFSET);
-  if (return_val_rtx != ret_val)
-    emit_move_insn (ret_val, return_val_rtx);
-#endif
-  
-  end = gen_label_rtx ();
-  emit_jump (end);  
-
-  RTL_EXPR_SEQUENCE (expr) = get_insns ();
-  end_sequence ();
-
-  expand_eh_region_end (expr);
-
-  emit_jump (end);
-
-#ifndef JUMP_TO_THROW
-  emit_label (label);
-  emit_throw ();
-#endif
-  
-  expand_leftover_cleanups ();
-
-  emit_label (end);
-}
-
-/* If necessary, emit insns for the per function unwinder for the
-   current function.  Called after all the code that needs unwind
-   protection is output.  
-
-   The unwinder takes care of catching any exceptions that have not
-   been previously caught within the function, unwinding the stack to
-   the next frame, and rethrowing using the address of the current
-   function's caller as the context of the throw.
-
-   On some platforms __throw can do this by itself (or with the help
-   of __unwind_function) so the per-function unwinder is
-   unnecessary.
-  
-   We cannot place the unwinder into the function until after we know
-   we are done inlining, as we don't want to have more than one
-   unwinder per non-inlined function.  */
-
-void
-emit_unwinder ()
-{
-  rtx insns, insn;
-
-  start_sequence ();
-  start_eh_unwinder ();
-  insns = get_insns ();
-  end_sequence ();
-
-  /* We place the start of the exception region associated with the
-     per function unwinder at the top of the function.  */
-  if (insns)
-    emit_insns_after (insns, get_insns ());
-
-  start_sequence ();
-  end_eh_unwinder ();
-  insns = get_insns ();
-  end_sequence ();
-
-  /* And we place the end of the exception region before the USE and
-     CLOBBER insns that may come at the end of the function.  */
-  if (insns == 0)
-    return;
-
-  insn = get_last_insn ();
-  while (GET_CODE (insn) == NOTE
-        || (GET_CODE (insn) == INSN
-            && (GET_CODE (PATTERN (insn)) == USE
-                || GET_CODE (PATTERN (insn)) == CLOBBER)))
-    insn = PREV_INSN (insn);
-
-  if (GET_CODE (insn) == CODE_LABEL
-      && GET_CODE (PREV_INSN (insn)) == BARRIER)
-    {
-      insn = PREV_INSN (insn);
-    }
-  else
-    {
-      rtx label = gen_label_rtx ();
-      emit_label_after (label, insn);
-      insn = emit_jump_insn_after (gen_jump (label), insn);
-      insn = emit_barrier_after (insn);
-    }
-    
-  emit_insns_after (insns, insn);
+  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+    if (GET_CODE (insn) == INSN
+       && GET_CODE (PATTERN (insn)) == USE)
+      {
+       rtx reg = find_reg_note (insn, REG_EH_CONTEXT, 0);
+       if (reg)
+         {
+           rtx insns;
+           
+           start_sequence ();
+
+           /* If this is the first use insn, emit the call here.  This
+              will always be at the top of our function, because if
+              expand_inline_function notices a REG_EH_CONTEXT note, it
+              adds a use insn to this function as well.  */
+           if (ehc == 0)
+             ehc = call_get_eh_context ();
+
+           emit_move_insn (XEXP (reg, 0), ehc);
+           insns = get_insns ();
+           end_sequence ();
+
+           emit_insns_before (insns, insn);
+         }
+      }
 }
 
 /* Scan the current insns and build a list of handler labels. The
@@ -1717,7 +1684,10 @@ find_exception_handler_labels ()
 
   /* Generate a handy reference to each label.  */
 
-  labels = (rtx *) alloca ((max_labelno - min_labelno) * sizeof (rtx));
+  /* We call xmalloc here instead of alloca; we did the latter in the past,
+     but found that it can sometimes end up being asked to allocate space
+     for more than 1 million labels.  */
+  labels = (rtx *) xmalloc ((max_labelno - min_labelno) * sizeof (rtx));
   bzero ((char *) labels, (max_labelno - min_labelno) * sizeof (rtx));
 
   /* Arrange for labels to be indexed directly by CODE_LABEL_NUMBER.  */
@@ -1757,6 +1727,8 @@ find_exception_handler_labels ()
            warning ("mismatched EH region %d", NOTE_BLOCK_NUMBER (insn));
        }
     }
+
+  free (labels + min_labelno);
 }
 
 /* Perform sanity checking on the exception_handler_labels list.
@@ -1838,12 +1810,6 @@ init_eh ()
   /* Generate rtl to reference the variable in which the PC of the
      current context is saved.  */
   tree type = build_pointer_type (make_node (VOID_TYPE));
-
-  eh_saved_pc = build_decl (VAR_DECL, get_identifier ("__eh_pc"), type);
-  DECL_EXTERNAL (eh_saved_pc) = 1;
-  TREE_PUBLIC (eh_saved_pc) = 1;
-  make_decl_rtl (eh_saved_pc, NULL_PTR, 1);
-  eh_saved_pc_rtx = DECL_RTL (eh_saved_pc);
 }
 
 /* Initialize the per-function EH information.  */
@@ -1857,8 +1823,7 @@ init_eh_for_function ()
   false_label_stack = 0;
   caught_return_label_stack = 0;
   protect_list = NULL_TREE;
-  current_function_dhc = NULL_RTX;
-  current_function_dcc = NULL_RTX;
+  current_function_ehc = NULL_RTX;
 }
 
 /* Save some of the per-function EH info into the save area denoted by
@@ -1870,7 +1835,8 @@ void
 save_eh_status (p)
      struct function *p;
 {
-  assert (p != NULL);
+  if (p == NULL)
+    abort ();
 
   p->ehstack = ehstack;
   p->ehqueue = ehqueue;
@@ -1878,8 +1844,7 @@ save_eh_status (p)
   p->false_label_stack = false_label_stack;
   p->caught_return_label_stack = caught_return_label_stack;
   p->protect_list = protect_list;
-  p->dhc = current_function_dhc;
-  p->dcc = current_function_dcc;
+  p->ehc = current_function_ehc;
 
   init_eh ();
 }
@@ -1892,7 +1857,8 @@ void
 restore_eh_status (p)
      struct function *p;
 {
-  assert (p != NULL);
+  if (p == NULL)
+    abort ();
 
   protect_list = p->protect_list;
   caught_return_label_stack = p->caught_return_label_stack;
@@ -1900,8 +1866,7 @@ restore_eh_status (p)
   catch_clauses        = p->catch_clauses;
   ehqueue = p->ehqueue;
   ehstack = p->ehstack;
-  current_function_dhc = p->dhc;
-  current_function_dcc = p->dcc;
+  current_function_ehc = p->ehc;
 }
 \f
 /* This section is for the exception handling specific optimization
@@ -1957,11 +1922,12 @@ scan_region (insn, n, delete_outer)
   /* Assume we can delete the region.  */
   int delete = 1;
 
-  assert (insn != NULL_RTX
-         && GET_CODE (insn) == NOTE
-         && NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG
-         && NOTE_BLOCK_NUMBER (insn) == n
-         && delete_outer != NULL);
+  if (insn == NULL_RTX
+      || GET_CODE (insn) != NOTE
+      || NOTE_LINE_NUMBER (insn) != NOTE_INSN_EH_REGION_BEG
+      || NOTE_BLOCK_NUMBER (insn) != n
+      || delete_outer == NULL)
+    abort ();
 
   insn = NEXT_INSN (insn);
 
@@ -2048,10 +2014,6 @@ exception_optimize ()
   rtx insn, regions = NULL_RTX;
   int n;
 
-  /* The below doesn't apply to setjmp/longjmp EH.  */
-  if (exceptions_via_longjmp)
-    return;
-
   /* Remove empty regions.  */
   for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
     {
@@ -2067,3 +2029,161 @@ exception_optimize ()
        }
     }
 }
+\f
+/* Various hooks for the DWARF 2 __throw routine.  */
+
+/* Do any necessary initialization to access arbitrary stack frames.
+   On the SPARC, this means flushing the register windows.  */
+
+void
+expand_builtin_unwind_init ()
+{
+  /* Set this so all the registers get saved in our frame; we need to be
+     able to copy the saved values for any registers from frames we unwind. */
+  current_function_has_nonlocal_label = 1;
+
+#ifdef SETUP_FRAME_ADDRESSES
+  SETUP_FRAME_ADDRESSES ();
+#endif
+}
+
+/* Given a value extracted from the return address register or stack slot,
+   return the actual address encoded in that value.  */
+
+rtx
+expand_builtin_extract_return_addr (addr_tree)
+     tree addr_tree;
+{
+  rtx addr = expand_expr (addr_tree, NULL_RTX, Pmode, 0);
+  return eh_outer_context (addr);
+}
+
+/* Given an actual address in addr_tree, do any necessary encoding
+   and return the value to be stored in the return address register or
+   stack slot so the epilogue will return to that address.  */
+
+rtx
+expand_builtin_frob_return_addr (addr_tree)
+     tree addr_tree;
+{
+  rtx addr = expand_expr (addr_tree, NULL_RTX, Pmode, 0);
+#ifdef RETURN_ADDR_OFFSET
+  addr = plus_constant (addr, -RETURN_ADDR_OFFSET);
+#endif
+  return addr;
+}
+
+/* Given an actual address in addr_tree, set the return address register up
+   so the epilogue will return to that address.  If the return address is
+   not in a register, do nothing.  */
+
+void
+expand_builtin_set_return_addr_reg (addr_tree)
+     tree addr_tree;
+{
+  rtx tmp;
+  rtx ra = expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS,
+                                      0, hard_frame_pointer_rtx);
+
+  if (GET_CODE (ra) != REG || REGNO (ra) >= FIRST_PSEUDO_REGISTER)
+    return;
+
+  tmp = force_operand (expand_builtin_frob_return_addr (addr_tree), ra);
+  if (tmp != ra)
+    emit_move_insn (ra, tmp);
+}
+
+/* Choose two registers for communication between the main body of
+   __throw and the stub for adjusting the stack pointer.  The first register
+   is used to pass the address of the exception handler; the second register
+   is used to pass the stack pointer offset.
+
+   For register 1 we use the return value register for a void *.
+   For register 2 we use the static chain register if it exists and is
+     different from register 1, otherwise some arbitrary call-clobbered
+     register.  */
+
+static void
+eh_regs (r1, r2, outgoing)
+     rtx *r1, *r2;
+     int outgoing;
+{
+  rtx reg1, reg2;
+
+#ifdef FUNCTION_OUTGOING_VALUE
+  if (outgoing)
+    reg1 = FUNCTION_OUTGOING_VALUE (build_pointer_type (void_type_node),
+                                   current_function_decl);
+  else
+#endif
+    reg1 = FUNCTION_VALUE (build_pointer_type (void_type_node),
+                          current_function_decl);
+
+#ifdef STATIC_CHAIN_REGNUM
+  if (outgoing)
+    reg2 = static_chain_incoming_rtx;
+  else
+    reg2 = static_chain_rtx;
+  if (REGNO (reg2) == REGNO (reg1))
+#endif /* STATIC_CHAIN_REGNUM */
+    reg2 = NULL_RTX;
+
+  if (reg2 == NULL_RTX)
+    {
+      int i;
+      for (i = 0; i < FIRST_PSEUDO_REGISTER; ++i)
+       if (call_used_regs[i] && ! fixed_regs[i] && i != REGNO (reg1))
+         {
+           reg2 = gen_rtx (REG, Pmode, i);
+           break;
+         }
+
+      if (reg2 == NULL_RTX)
+       abort ();
+    }
+
+  *r1 = reg1;
+  *r2 = reg2;
+}
+
+/* Emit inside of __throw a stub which adjusts the stack pointer and jumps
+   to the exception handler.  __throw will set up the necessary values
+   and then return to the stub.  */
+
+rtx
+expand_builtin_eh_stub ()
+{
+  rtx stub_start = gen_label_rtx ();
+  rtx after_stub = gen_label_rtx ();
+  rtx handler, offset, temp;
+
+  emit_jump (after_stub);
+  emit_label (stub_start);
+
+  eh_regs (&handler, &offset, 0);
+
+  adjust_stack (offset);
+  emit_indirect_jump (handler);
+
+  emit_label (after_stub);
+  return gen_rtx (LABEL_REF, Pmode, stub_start);
+}
+
+/* Set up the registers for passing the handler address and stack offset
+   to the stub above.  */
+
+void
+expand_builtin_set_eh_regs (handler, offset)
+     tree handler, offset;
+{
+  rtx reg1, reg2;
+
+  eh_regs (&reg1, &reg2, 1);
+
+  store_expr (offset,  reg2, 0);
+  store_expr (handler, reg1, 0);
+
+  /* These will be used by the stub.  */
+  emit_insn (gen_rtx (USE, VOIDmode, reg1));
+  emit_insn (gen_rtx (USE, VOIDmode, reg2));
+}
This page took 0.058907 seconds and 5 git commands to generate.