EH rethrow patch

Andrew Macleod amacleod@cygnus.com
Tue Dec 8 17:56:00 GMT 1998


I've applied this patch to the latest egcs sources.

This enables exception handling to have a sepereate rethrow library
function, instead of the mechanism we use to use, and it also makes 
some nice improvements to the EH code in general. Most of it is only 
available under -fnew-exceptions.

__unwinding_cleanup is a hook function which you can put a break point 
on in the debugger. This function is called by __throw before
running cleanups when an exception is not going to be caught,
and __terminate is going to eventually be called. Now you can see your
stack frame BEFORE unwinding happens.  This is only available 
with -fnew-exceptions.

Handler code is a bit smaller in general.

There is no longer any jump around code at the end of regions to 
handle rethrows, so straight line code is actually straight now :-)

In some cases, we end up with more exception regions than we had before,
generally because the region is used as a rethrow target. Eventually
I'll go through and eliminate all of these. For now, I want to get this
code enabled. 

As far as I know, -fnew-exceptions is binary compatible with the normal
exception handling mechanism, as long as you are linking to the new 
library routines in libgcc and not some older version of libgcc.

As always, -fnew-exceptions ONLY applies to targets with the DWARF2
table dirven mechanism. The setjmp/longjmp mechanism is unaffected
by this. 

Please let me know if you run into binary incompatabilities, or failures
which you didn't use to have. This s true even if you are not 
using -fnew-exceptions since I've changed a lot of the underlying stuff too.

Andrew

------------------------------------------------------------------------------


	* eh-common.h (struct eh_context): Add table_index for rethrows.

	* rtl.h (enum reg_note): Add REG_EH_REGION and REG_EH_RETHROW reg notes.
	(SYMBOL_REF_NEED_ADJUST): New flag indicating symbol needs to be
	processed when inlined or unrolled (ie duplicated in some way).

	* rtl.c (reg_note_name): Add strings for new reg_note enums.

	* expr.h (rethrow_libfunc): New library decl.

	* optabs.c (rethrow_libfunc): Initialize.

	* except.h (struct eh_entry): Add new field 'rethrow_label'.
	(new_eh_region_entry): No longer exported from except.c.
	(duplicate_handlers): Renamed to duplicate_eh_handlers and 
	different prototype.
	(rethrow_symbol_map, rethrow_used): New exported functions.
	(eh_region_from_symbol): New exported function.

	* except.c (create_rethrow_ref): New function to create a single
	SYMBOL_REF for a rethrow region.  
        (push_eh_entry): Initialize a rethrow ref.
	(func_eh_entry): Add a rethrow_label field.
	(new_eh_region_entry): Make static, and initialize the rethrow entry.
	(duplicate_eh_handlers): Create a new region, and remap labels/symbols.
	(eh_region_from_symbol): Find an EH region based on its rethrow symbol.
	(rethrow_symbol_map): Given a label map, maps a rethrow symbol for 
	a region into an appropriate new symbol.
	(rethrow_used): Indicate whether a rethrow symbol has been referenced.
	(expand_eh_region_end): Don't issue jump around code for new-exceptions.
	(end_catch_handler): Emit a barrier for new-exceptions since 
	control can never drop through the end of a catch block.
	(expand_end_all_catch): new-exceptions never fall through a catch 
	block.
	(expand_rethrow): use __rethrow routine for new exceptions.
	(output_exception_table_entry): Generate rethrow labels, if needed.
	(output_exception_table): Generate start and end rethrow labels.
	(init_eh): Create rethrow symbols for beginning and end of table.
	(scan_region): Don't eliminate EH regions which are the targets of
	rethrows.

	* flow.c (make_edges): Add different edges for rethrow calls, 
	identified by having the REG_EH_RETHROW reg label.
	(delete_unreachable_blocks): Don't delete regions markers which are 
	the target of a rethrow.

	* integrate.c (save_for_inline_eh_labelmap): New callback routine to 
	allow save_for_inline_copying to call duplicate_eh_handlers.
	(save_for_inline_copying): Call duplicate_eh_handlers instead of
	exposing internal details of exception regions.
	(copy_for_inline): Check if SYMBOL_REFs need adjustment.
	(expand_inline_function_eh_labelmap):  New callback routine to 
	allow expand_inline_function to call duplicate_eh_handlers.
	(expand_inline_function): Call duplicate_eh_handlers instead of
	exposing internal details of exception regions.
	(copy_rtx_and_substitute): Adjust SYMBOL_REFS if SYMBOL_REF_NEED_ADJUST
	flag is set.

	* libgcc2.c (find_exception_handler): Generalize to enable it to
	pick up processing where it left off last time for a rethrow.
	(__unwinding_cleanup): New function. debug hook which is called before
	unwinding when __throw finds there is nothing but cleanups left.
	(throw_helper): Common parts of __throw extracted out for reuse.
	(__throw): Common parts moved to throw_helper.
	(__rethrow): New function for performing rethrows.

	* cp/except.c (call_eh_info): use __start_cp_handler instead of
	__cp_eh_info for getting the eh info pointer. Add table_index to
	field list.
	(push_eh_cleanup): Don't increment 'handlers' data field.
	(process_start_catch_block): Don't set the 'caught' field.

	* cp/exception.cc (CP_EH_INFO): New macro for getting the 
	exception info pointer within library routines.
	(__cp_eh_info): Use CP_EH_INFO.
	(__start_cp_handler): Get exception info pointer, set caught field,
	and increment the handlers field. Avoids this being done by handlers.
	(__uncatch_exception, __check_eh_spec): Use CP_EH_INFO macro.
	(uncaught_exception): Use CP_EH_INFO macro.


Index: gcc/eh-common.h
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/eh-common.h,v
retrieving revision 1.5
diff -c -p -r1.5 eh-common.h
*** eh-common.h	1998/06/25 14:11:45	1.5
--- eh-common.h	1998/11/10 15:06:10
*************** struct eh_context
*** 31,36 ****
--- 31,38 ----
    void **dynamic_handler_chain;
    /* This is language dependent part of the eh context. */
    void *info;
+   /* This is used to remember where we threw for re-throws */
+   void *table_index;  /* address of exception table entry to rethrow from */
  };
  
  #ifndef EH_TABLE_LOOKUP
Index: gcc/rtl.h
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/rtl.h,v
retrieving revision 1.62
diff -c -p -r1.62 rtl.h
*** rtl.h	1998/10/29 23:18:50	1.62
--- rtl.h	1998/11/10 15:06:12
*************** typedef struct rtvec_def{
*** 342,347 ****
--- 342,355 ----
       REG_FRAME_RELATED_EXPR is attached to insns that are RTX_FRAME_RELATED_P,
     but are too complex for DWARF to interpret what they imply.  The attached
     rtx is used instead of intuition.  */
+ /*   REG_EH_REGION is used to indicate what exception region an INSN
+    belongs in. This can be used to indicate what region a call may throw
+    to. a REGION of 0 indicates that a call cannot throw at all.
+      REG_EH_RETHROW is used to indicate what that a call is actually a
+    call to rethrow, and specifies which region the rethrow is targetting.
+    This provides a way to generate the non standard flow edges required 
+    for a rethrow. */
+    
  
  #define REG_NOTES(INSN)	((INSN)->fld[6].rtx)
  
*************** enum reg_note { REG_DEAD = 1, REG_INC = 
*** 355,361 ****
  		REG_DEP_ANTI = 14, REG_DEP_OUTPUT = 15, REG_BR_PROB = 16,
  		REG_EXEC_COUNT = 17, REG_NOALIAS = 18, REG_SAVE_AREA = 19,
  		REG_BR_PRED = 20, REG_EH_CONTEXT = 21,
! 		REG_FRAME_RELATED_EXPR = 22 };
  /* The base value for branch probability notes.  */
  #define REG_BR_PROB_BASE  10000
  
--- 363,370 ----
  		REG_DEP_ANTI = 14, REG_DEP_OUTPUT = 15, REG_BR_PROB = 16,
  		REG_EXEC_COUNT = 17, REG_NOALIAS = 18, REG_SAVE_AREA = 19,
  		REG_BR_PRED = 20, REG_EH_CONTEXT = 21,
! 		REG_FRAME_RELATED_EXPR = 22, REG_EH_REGION = 23,
! 		REG_EH_RETHROW = 24 };
  /* The base value for branch probability notes.  */
  #define REG_BR_PROB_BASE  10000
  
*************** extern char *note_insn_name[];
*** 618,623 ****
--- 627,636 ----
  
  /* Flag in a SYMBOL_REF for machine-specific purposes.  */
  #define SYMBOL_REF_FLAG(RTX) ((RTX)->volatil)
+ 
+ /* 1 in a SYMBOL_REF if it represents a symbol which might have to change
+    if its inlined or unrolled. */
+ #define SYMBOL_REF_NEED_ADJUST(RTX)  ((RTX)->in_struct)
  
  /* 1 means a SYMBOL_REF has been the library function in emit_library_call.  */
  #define SYMBOL_REF_USED(RTX) ((RTX)->used)
Index: gcc/rtl.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/rtl.c,v
retrieving revision 1.22
diff -c -p -r1.22 rtl.c
*** rtl.c	1998/10/23 04:09:58	1.22
--- rtl.c	1998/11/10 15:06:13
*************** char *reg_note_name[] = { "", "REG_DEAD"
*** 193,199 ****
  			  "REG_DEP_ANTI", "REG_DEP_OUTPUT", "REG_BR_PROB",
  			  "REG_EXEC_COUNT", "REG_NOALIAS", "REG_SAVE_AREA",
  			  "REG_BR_PRED", "REG_EH_CONTEXT",
! 			  "REG_FRAME_RELATED_EXPR" };
  
  static void dump_and_abort	PROTO((int, int, FILE *)) ATTRIBUTE_NORETURN;
  static void read_name		PROTO((char *, FILE *));
--- 193,200 ----
  			  "REG_DEP_ANTI", "REG_DEP_OUTPUT", "REG_BR_PROB",
  			  "REG_EXEC_COUNT", "REG_NOALIAS", "REG_SAVE_AREA",
  			  "REG_BR_PRED", "REG_EH_CONTEXT",
! 			  "REG_FRAME_RELATED_EXPR", "REG_EH_REGION",
! 			  "REG_EH_RETHROW" };
  
  static void dump_and_abort	PROTO((int, int, FILE *)) ATTRIBUTE_NORETURN;
  static void read_name		PROTO((char *, FILE *));
Index: gcc/expr.h
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/expr.h,v
retrieving revision 1.25
diff -c -p -r1.25 expr.h
*** expr.h	1998/10/11 02:21:29	1.25
--- expr.h	1998/11/10 15:06:14
*************** extern rtx memset_libfunc;
*** 441,446 ****
--- 441,447 ----
  extern rtx bzero_libfunc;
  
  extern rtx throw_libfunc;
+ extern rtx rethrow_libfunc;
  extern rtx sjthrow_libfunc;
  extern rtx sjpopnthrow_libfunc;
  extern rtx terminate_libfunc;
Index: gcc/optabs.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/optabs.c,v
retrieving revision 1.17
diff -c -p -r1.17 optabs.c
*** optabs.c	1998/10/17 20:26:24	1.17
--- optabs.c	1998/11/10 15:06:19
*************** rtx memset_libfunc;
*** 119,124 ****
--- 119,125 ----
  rtx bzero_libfunc;
  
  rtx throw_libfunc;
+ rtx rethrow_libfunc;
  rtx sjthrow_libfunc;
  rtx sjpopnthrow_libfunc;
  rtx terminate_libfunc;
*************** init_optabs ()
*** 4294,4299 ****
--- 4295,4301 ----
    bzero_libfunc = gen_rtx_SYMBOL_REF (Pmode, "bzero");
  
    throw_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__throw");
+   rethrow_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__rethrow");
    sjthrow_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__sjthrow");
    sjpopnthrow_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__sjpopnthrow");
    terminate_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__terminate");
Index: gcc/except.h
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/except.h,v
retrieving revision 1.24
diff -c -p -r1.24 except.h
*** except.h	1998/09/15 19:18:51	1.24
--- except.h	1998/11/10 15:06:19
*************** struct eh_entry {
*** 65,70 ****
--- 65,71 ----
    tree finalization;
    int label_used;
    rtx false_label;
+   rtx rethrow_label;
  };
  
  /* A list of EH_ENTRYs. ENTRY is the entry; CHAIN points to the next
*************** typedef struct handler_info 
*** 177,189 ****
  } handler_info;
  
  
- /* Add a new eh_entry for this function, The parameter specifies what
-    exception region number NOTE insns use to delimit this range. 
-    The integer returned is uniquely identifies this exception range
-    within an internal table. */
- 
- int new_eh_region_entry                         PROTO((int));
- 
  /* Add new handler information to an exception range. The  first parameter
     specifies the range number (returned from new_eh_entry()). The second
     parameter specifies the handler.  By default the handler is inserted at
--- 178,183 ----
*************** struct handler_info *get_new_handler    
*** 207,215 ****
  
  /* Make a duplicate of an exception region by copying all the handlers
     for an exception region. Return the new handler index. */
  
! int duplicate_handlers                          PROTO((int, int));
  
  
  /* Get a pointer to the first handler in an exception region's list. */
  
--- 201,220 ----
  
  /* Make a duplicate of an exception region by copying all the handlers
     for an exception region. Return the new handler index. */
+ 
+ int duplicate_eh_handlers                       PROTO((int, int, rtx (*)(rtx)));
+ 
+ /* map symbol refs for rethrow */
+ 
+ rtx rethrow_symbol_map                          PROTO((rtx, rtx (*)(rtx)));
+ 
+ /* Is the rethrow label for a region used? */
+ 
+ int rethrow_used                                PROTO((int));
  
! /* Return the region number a this is the rethrow label for. */
  
+ int eh_region_from_symbol                       PROTO((rtx));
  
  /* Get a pointer to the first handler in an exception region's list. */
  
Index: gcc/except.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/except.c,v
retrieving revision 1.69
diff -c -p -r1.69 except.c
*** except.c	1998/11/05 05:34:01	1.69
--- except.c	1998/11/10 15:06:22
*************** Boston, MA 02111-1307, USA.  */
*** 406,411 ****
--- 406,412 ----
  #include "recog.h"
  #include "output.h"
  #include "toplev.h"
+ #include "obstack.h"
  
  /* One to use setjmp/longjmp method of generating code for exception
     handling.  */
*************** static rtx eh_return_handler;
*** 502,507 ****
--- 503,517 ----
  
  rtx eh_return_stub_label;
  
+ /* This is used for targets which can call rethrow with an offset instead
+    of an address. This is subtracted from the rethrow label we are
+    interested in. */
+ 
+ static rtx first_rethrow_symbol = NULL_RTX;
+ static rtx final_rethrow = NULL_RTX;
+ static rtx last_rethrow_symbol = NULL_RTX;
+ 
+ 
  /* Prototypes for local functions.  */
  
  static void push_eh_entry	PROTO((struct eh_stack *));
*************** rtx expand_builtin_return_addr	PROTO((en
*** 526,531 ****
--- 536,564 ----
  /* Various support routines to manipulate the various data structures
     used by the exception handling code.  */
  
+ 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;
+   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));
+   def = gen_rtx_SYMBOL_REF (Pmode, ptr);
+   SYMBOL_REF_NEED_ADJUST (def) = 1;
+ 
+   pop_obstacks ();
+   return def;
+ }
+ 
  /* Push a label entry onto the given STACK.  */
  
  void
*************** push_eh_entry (stack)
*** 600,610 ****
    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->outer_context = gen_label_rtx ();
    entry->finalization = NULL_TREE;
    entry->label_used = 0;
!   entry->exception_handler_label = gen_exception_label ();
    entry->false_label = NULL_RTX;
  
    node->entry = entry;
    node->chain = stack->top;
--- 633,648 ----
    struct eh_node *node = (struct eh_node *) xmalloc (sizeof (struct eh_node));
    struct eh_entry *entry = (struct eh_entry *) xmalloc (sizeof (struct eh_entry));
  
!   rtx rlab = gen_exception_label ();
    entry->finalization = NULL_TREE;
    entry->label_used = 0;
!   entry->exception_handler_label = rlab;
    entry->false_label = NULL_RTX;
+   if (! flag_new_exceptions)
+     entry->outer_context = gen_label_rtx ();
+   else
+     entry->outer_context = create_rethrow_ref (CODE_LABEL_NUMBER (rlab));
+   entry->rethrow_label = entry->outer_context;
  
    node->entry = entry;
    node->chain = stack->top;
*************** receive_exception_label (handler_label)
*** 707,712 ****
--- 745,751 ----
  struct func_eh_entry 
  {
    int range_number;   /* EH region number from EH NOTE insn's */
+   rtx rethrow_label;  /* Label for rethrow */
    struct handler_info *handlers;
  };
  
*************** static int current_func_eh_entry = 0;
*** 719,730 ****
  #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. The number
     returned is an number which uniquely identifies this exception range. */
  
! int 
! new_eh_region_entry (note_eh_region) 
       int note_eh_region;
  {
    if (current_func_eh_entry == num_func_eh_entries) 
      {
--- 758,771 ----
  #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. */
  
! static int 
! new_eh_region_entry (note_eh_region, rethrow) 
       int note_eh_region;
+      rtx rethrow;
  {
    if (current_func_eh_entry == num_func_eh_entries) 
      {
*************** new_eh_region_entry (note_eh_region) 
*** 742,747 ****
--- 783,793 ----
          }
      }
    function_eh_regions[current_func_eh_entry].range_number = note_eh_region;
+   if (rethrow == NULL_RTX)
+     function_eh_regions[current_func_eh_entry].rethrow_label = 
+                                           create_rethrow_ref (note_eh_region);
+   else
+     function_eh_regions[current_func_eh_entry].rethrow_label = rethrow;
    function_eh_regions[current_func_eh_entry].handlers = NULL;
  
    return current_func_eh_entry++;
*************** clear_function_eh_region ()
*** 924,957 ****
  }
  
  /* Make a duplicate of an exception region by copying all the handlers
!    for an exception region. Return the new handler index. */
  
  int 
! duplicate_handlers (old_note_eh_region, new_note_eh_region)
       int old_note_eh_region, new_note_eh_region;
  {
    struct handler_info *ptr, *new_ptr;
    int new_region, region;
  
    region = find_func_region (old_note_eh_region);
    if (region == -1)
!     error ("Cannot duplicate non-existant exception region.");
  
!   if (find_func_region (new_note_eh_region) != -1)
!     error ("Cannot duplicate EH region because new note region already exists");
  
-   new_region = new_eh_region_entry (new_note_eh_region);
    ptr = function_eh_regions[region].handlers;
  
    for ( ; ptr; ptr = ptr->next) 
      {
!       new_ptr = get_new_handler (ptr->handler_label, ptr->type_info);
        add_new_handler (new_region, new_ptr);
      }
  
    return new_region;
  }
  
  
  /* Routine to see if exception handling is turned on.
     DO_WARN is non-zero if we want to inform the user that exception
--- 970,1067 ----
  }
  
  /* Make a duplicate of an exception region by copying all the handlers
!    for an exception region. Return the new handler index. The final
!    parameter is a routine which maps old labels to new ones. */
  
  int 
! duplicate_eh_handlers (old_note_eh_region, new_note_eh_region, map)
       int old_note_eh_region, new_note_eh_region;
+      rtx (*map)(rtx);
  {
    struct handler_info *ptr, *new_ptr;
    int new_region, region;
+   rtx tmp;
  
    region = find_func_region (old_note_eh_region);
    if (region == -1)
!     fatal ("Cannot duplicate non-existant exception region.");
! 
!   /* duplicate_eh_handlers may have been called during a symbol remap. */
!   new_region = find_func_region (new_note_eh_region);
!   if (new_region != -1)
!     return (new_region);
  
!   new_region = new_eh_region_entry (new_note_eh_region, NULL_RTX);
  
    ptr = function_eh_regions[region].handlers;
  
    for ( ; ptr; ptr = ptr->next) 
      {
!       new_ptr = get_new_handler (map (ptr->handler_label), ptr->type_info);
        add_new_handler (new_region, new_ptr);
      }
  
    return new_region;
  }
  
+ 
+ /* Given a rethrow symbol, find the EH region number this is for. */
+ int 
+ eh_region_from_symbol (sym)
+      rtx sym;
+ {
+   int x;
+   if (sym == last_rethrow_symbol)
+     return 1;
+   for (x = 0; x < current_func_eh_entry; x++)
+     if (function_eh_regions[x].rethrow_label == sym)
+       return function_eh_regions[x].range_number;
+   return -1;
+ }
+ 
+ 
+ /* 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)(rtx);
+ {
+   int x, y;
+   for (x = 0; x < current_func_eh_entry; x++)
+     if (function_eh_regions[x].rethrow_label == sym)
+       {
+         /* We've found the original region, now lets determine which region
+            this now maps to. */
+         rtx l1 = function_eh_regions[x].handlers->handler_label;
+         rtx l2 = map (l1);
+         y = CODE_LABEL_NUMBER (l2); /* This is the new region number */
+         x = find_func_region (y);  /* Get the new permanent region */
+         if (x == -1)  /* Hmm, Doesn't exist yet */
+           {
+             x = duplicate_eh_handlers (CODE_LABEL_NUMBER (l1), y, map);
+             /* Since we're mapping it, it must be used. */
+             SYMBOL_REF_USED (function_eh_regions[x].rethrow_label) = 1;
+           }
+         return function_eh_regions[x].rethrow_label;
+       }
+   return sym;
+ }
+ 
+ int 
+ rethrow_used (region)
+      int region;
+ {
+   if (flag_new_exceptions)
+     {
+       rtx lab = function_eh_regions[find_func_region (region)].rethrow_label;
+       return (SYMBOL_REF_USED (lab));
+     }
+   return 0;
+ }
+ 
  
  /* Routine to see if exception handling is turned on.
     DO_WARN is non-zero if we want to inform the user that exception
*************** expand_eh_region_end (handler)
*** 1405,1410 ****
--- 1515,1521 ----
  {
    struct eh_entry *entry;
    rtx note;
+   int ret, r;
  
    if (! doing_eh (0))
      return;
*************** expand_eh_region_end (handler)
*** 1412,1420 ****
    entry = pop_eh_entry (&ehstack);
  
    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)
      {
--- 1523,1531 ----
    entry = pop_eh_entry (&ehstack);
  
    note = emit_note (NULL_PTR, NOTE_INSN_EH_REGION_END);
!   ret = NOTE_BLOCK_NUMBER (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.  */
        && INSN_UID (entry->outer_context) == 0)
      {
*************** expand_eh_region_end (handler)
*** 1434,1440 ****
    entry->finalization = handler;
  
    /* create region entry in final exception table */
!   new_eh_region_entry (NOTE_BLOCK_NUMBER (note));
  
    enqueue_eh_entry (&ehqueue, entry);
  
--- 1545,1551 ----
    entry->finalization = handler;
  
    /* create region entry in final exception table */
!   r = new_eh_region_entry (NOTE_BLOCK_NUMBER (note), entry->rethrow_label);
  
    enqueue_eh_entry (&ehqueue, entry);
  
*************** start_catch_handler (rtime)
*** 1668,1675 ****
  void 
  end_catch_handler ()
  {
!   if (! doing_eh (1) || (flag_new_exceptions && ! exceptions_via_longjmp))
      return;
    
    /* A NULL label implies the catch clause was a catch all or cleanup */
    if (catchstack.top->entry->false_label == NULL_RTX)
--- 1779,1792 ----
  void 
  end_catch_handler ()
  {
!   if (! doing_eh (1))
      return;
+ 
+   if (flag_new_exceptions && ! exceptions_via_longjmp) 
+     {
+       emit_barrier ();
+       return;
+     }
    
    /* A NULL label implies the catch clause was a catch all or cleanup */
    if (catchstack.top->entry->false_label == NULL_RTX)
*************** expand_start_all_catch ()
*** 1781,1787 ****
  void
  expand_end_all_catch ()
  {
!   rtx new_catch_clause, outer_context = NULL_RTX;
    struct eh_entry *entry;
  
    if (! doing_eh (1))
--- 1898,1904 ----
  void
  expand_end_all_catch ()
  {
!   rtx new_catch_clause;
    struct eh_entry *entry;
  
    if (! doing_eh (1))
*************** expand_end_all_catch ()
*** 1793,1803 ****
  
    if (! exceptions_via_longjmp)
      {
!       outer_context = ehstack.top->entry->outer_context;
  
        /* 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
--- 1910,1926 ----
  
    if (! exceptions_via_longjmp)
      {
!       rtx outer_context = ehstack.top->entry->outer_context;
  
        /* Finish the rethrow region.  size_zero_node is just a NOP.  */
        expand_eh_region_end (size_zero_node);
+       /* New exceptions handling models will never have a fall through
+          of a catch clause */
+       if (!flag_new_exceptions)
+         expand_rethrow (outer_context);
      }
+   else 
+     expand_rethrow (NULL_RTX);
  
    /* 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
*************** expand_end_all_catch ()
*** 1808,1814 ****
       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 ();
--- 1931,1936 ----
*************** expand_rethrow (label)
*** 1837,1843 ****
    if (exceptions_via_longjmp)
      emit_throw ();
    else
!     emit_jump (label);
  }
  
  /* End all the pending exception regions on protect_list. The handlers
--- 1959,1980 ----
    if (exceptions_via_longjmp)
      emit_throw ();
    else
!     if (flag_new_exceptions)
!       {
!         rtx insn, val;
!         if (label == NULL_RTX)
!           label = last_rethrow_symbol;
!         emit_library_call (rethrow_libfunc, 0, VOIDmode, 1, label, Pmode);
!         SYMBOL_REF_USED (label) = 1;
!         insn = get_last_insn ();
!         val = GEN_INT (eh_region_from_symbol (label));
!         /* Mark the label/symbol on the call. */
!         REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EH_RETHROW, val,
!                                      REG_NOTES (insn));
!         emit_barrier ();
!       }
!     else
!       emit_jump (label);
  }
  
  /* End all the pending exception regions on protect_list. The handlers
*************** output_exception_table_entry (file, n)
*** 1971,1982 ****
  {
    char buf[256];
    rtx sym;
!   struct handler_info *handler;
  
-   handler = get_first_handler (n);
  
!   for ( ; handler != NULL; handler = handler->next)
      {
        ASM_GENERATE_INTERNAL_LABEL (buf, "LEHB", n);
        sym = gen_rtx_SYMBOL_REF (Pmode, buf);
        assemble_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1);
--- 2108,2136 ----
  {
    char buf[256];
    rtx sym;
!   struct handler_info *handler = get_first_handler (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 (! SYMBOL_REF_USED (rethrow))
!       rethrow = NULL_RTX;
  
  
!   for ( ; handler != NULL || rethrow != NULL_RTX; handler = handler->next)
      {
+       /* rethrow label should indicate the LAST entry for a region */
+       if (rethrow != NULL_RTX && (handler == NULL || handler->next == NULL))
+         {
+           ASM_GENERATE_INTERNAL_LABEL (buf, "LRTH", n);
+           assemble_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);
*************** output_exception_table_entry (file, n)
*** 1985,1996 ****
        sym = gen_rtx_SYMBOL_REF (Pmode, buf);
        assemble_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1);
        
!       assemble_integer (handler->handler_label, 
!                                          POINTER_SIZE / BITS_PER_UNIT, 1);
  
        if (flag_new_exceptions)
          {
!           if (handler->type_info == NULL)
              assemble_integer (const0_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
            else
              if (handler->type_info == CATCH_ALL_TYPE)
--- 2139,2153 ----
        sym = gen_rtx_SYMBOL_REF (Pmode, buf);
        assemble_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1);
        
!       if (handler == NULL)
!         assemble_integer (GEN_INT (0), POINTER_SIZE / BITS_PER_UNIT, 1);
!       else
!         assemble_integer (handler->handler_label, 
!                           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);
            else
              if (handler->type_info == CATCH_ALL_TYPE)
*************** output_exception_table_entry (file, n)
*** 2002,2008 ****
          }
        putc ('\n', file);		/* blank line */
        /* We only output the first label under the old scheme */
!       if (! flag_new_exceptions)
          break;
      }
  }
--- 2159,2165 ----
          }
        putc ('\n', file);		/* blank line */
        /* We only output the first label under the old scheme */
!       if (! flag_new_exceptions || handler == NULL)
          break;
      }
  }
*************** void
*** 2033,2038 ****
--- 2190,2196 ----
  output_exception_table ()
  {
    int i;
+   char buf[256];
    extern FILE *asm_out_file;
  
    if (! doing_eh (0) || ! eh_table)
*************** output_exception_table ()
*** 2057,2062 ****
--- 2215,2224 ----
          ;
        if (i != 0)
          assemble_integer (const0_rtx, i , 1);
+ 
+       /* Generate the label for offset calculations on rethrows */
+       ASM_GENERATE_INTERNAL_LABEL (buf, "LRTH", 0);
+       assemble_label(buf);
      }
  
    for (i = 0; i < eh_table_size; ++i)
*************** output_exception_table ()
*** 2066,2071 ****
--- 2228,2236 ----
    clear_function_eh_region ();
  
    /* 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);
  
    /* for binary compatability, the old __throw checked the second
*************** check_exception_handler_labels ()
*** 2224,2229 ****
--- 2389,2398 ----
  void
  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));
  }
  
  /* Initialize the per-function EH information.  */
*************** scan_region (insn, n, delete_outer)
*** 2342,2347 ****
--- 2511,2521 ----
  
    /* Assume we can delete the region.  */
    int delete = 1;
+ 
+   int r = find_func_region (n);
+   /* Can't delete something which is rethrown to. */
+   if (SYMBOL_REF_USED((function_eh_regions[r].rethrow_label)))
+     delete = 0;
  
    if (insn == NULL_RTX
        || GET_CODE (insn) != NOTE
Index: gcc/flow.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/flow.c,v
retrieving revision 1.81
diff -c -p -r1.81 flow.c
*** flow.c	1998/10/29 23:18:47	1.81
--- flow.c	1998/11/10 15:06:26
*************** make_edges (i)
*** 718,723 ****
--- 718,724 ----
       int i;
  {
    rtx insn, x;
+   rtx pending_eh_region = NULL_RTX;
  
    /* See if control drops into the next block.  */
    if (i + 1 < n_basic_blocks)
*************** make_edges (i)
*** 798,803 ****
--- 799,838 ----
  		}
  	    }
  
+           /* If this is a call with an EH_RETHROW note, then we 
+              know its a rethrow call, and we know exactly where
+              this call can end up going. */
+           else if (GET_CODE (insn) == CALL_INSN
+                     && (note = find_reg_note (insn, REG_EH_RETHROW, NULL_RTX)))
+             {
+               int region = XINT (XEXP (note, 0), 0);
+               /* if nested region is not 0, we know for sure it has been 
+                  processed. If it is zero, we dont know whether its an
+                  outer region, or hasn't been seen yet, so defer it */
+               if (nested_eh_region[region] != 0) 
+                 {
+                   /* start with the first region OUTSIDE the one specified 
+                      in the rethrow parameter. (since a rethrow behaves
+                      as if a handler in the region didn't handle the 
+                      exception, so the handlers for the next outer region
+                      are going to get a shot at it.*/
+ 		  for ( region = nested_eh_region[region]; region; 
+ 			region = nested_eh_region[region]) 
+ 		    {
+ 		      handler_info *ptr = get_first_handler (region);
+ 		      for ( ; ptr ; ptr = ptr->next)
+                         add_edge_to_label (i, ptr->handler_label);
+ 		    }
+                 }
+               else 
+                 {
+                   /* Push this region onto a list, and after we've done the
+                      whole procedure, we'll process everything on the list */
+                   pending_eh_region = gen_rtx_EXPR_LIST (VOIDmode, insn, 
+                                                          pending_eh_region);
+                 }
+             }
+ 
  	  /* If this is a CALL_INSN, then mark it as reaching the active EH
  	     handler for this CALL_INSN.  If we're handling asynchronous
  	     exceptions mark every insn as reaching the active EH handler.
*************** make_edges (i)
*** 834,839 ****
--- 869,892 ----
  	    }
  	}
      }
+ 
+   while (pending_eh_region != NULL_RTX)
+     {
+       rtx insn = XEXP (pending_eh_region, 0);
+       rtx note = find_reg_note (insn, REG_EH_RETHROW, NULL_RTX);
+       int region = XINT (XEXP (note, 0), 0);
+       /* start with the first region OUTSIDE the one specified 
+          in the rethrow parameter */
+       for ( region = nested_eh_region[region]; region; 
+             region = nested_eh_region[region]) 
+         {
+           handler_info *ptr = get_first_handler (region);
+           for ( ; ptr ; ptr = ptr->next)
+             add_edge_to_label (BLOCK_NUM (insn), ptr->handler_label);
+         }
+       pending_eh_region = XEXP (pending_eh_region, 1);
+     }
+ 
    /* We know something about the structure of the function __throw in
       libgcc2.c.  It is the only function that ever contains eh_stub labels.
       It modifies its return address so that the last block returns to one of
*************** delete_unreachable_blocks ()
*** 915,922 ****
  	      NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_END)
  	    {
  	      int num = CODE_LABEL_NUMBER (insn);
! 	      /* A NULL handler indicates a region is no longer needed */
! 	      if (get_first_handler (num) == NULL)
  		{
  		  NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
  		  NOTE_SOURCE_FILE (insn) = 0;
--- 968,976 ----
  	      NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_END)
  	    {
  	      int num = CODE_LABEL_NUMBER (insn);
! 	      /* A NULL handler indicates a region is no longer needed,
!                  unless its the target of a rethrow. */
! 	      if (get_first_handler (num) == NULL && !rethrow_used (num))
  		{
  		  NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
  		  NOTE_SOURCE_FILE (insn) = 0;
Index: gcc/integrate.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/integrate.c,v
retrieving revision 1.39
diff -c -p -r1.39 integrate.c
*** integrate.c	1998/10/06 20:38:40	1.39
--- integrate.c	1998/11/10 15:06:30
*************** static rtvec copy_asm_constraints_vector
*** 265,270 ****
--- 265,280 ----
  /* In save_for_inline, nonzero if past the parm-initialization insns.  */
  static int in_nonparm_insns;
  
+ /* subroutines passed to duplicate_eh_handlers to map exception labels */
+ 
+ static rtx 
+ save_for_inline_eh_labelmap (label)
+      rtx label;
+ {
+   int index = CODE_LABEL_NUMBER (label);
+   return label_map[index];
+ }
+ 
  /* Subroutine for `save_for_inline{copying,nocopy}'.  Performs initialization
     needed to save FNDECL's insns and info for future inline expansion.  */
     
*************** save_for_inline_copying (fndecl)
*** 667,685 ****
  
                /* we have to duplicate the handlers for the original */
                if (NOTE_LINE_NUMBER (copy) == NOTE_INSN_EH_REGION_BEG) 
!                 {
!                   handler_info *ptr, *temp;
!                   int nr;
!                   nr = new_eh_region_entry (new_region);
!                   ptr = get_first_handler (NOTE_BLOCK_NUMBER (copy));
!                   for ( ; ptr; ptr = ptr->next)
!                     {
!                       temp = get_new_handler (
!                            label_map[CODE_LABEL_NUMBER (ptr->handler_label)],
!                                                                ptr->type_info);
!                       add_new_handler (nr, temp);
!                     }
!                 }
                  
  	      /* We have to forward these both to match the new exception
  		 region.  */
--- 677,684 ----
  
                /* we have to duplicate the handlers for the original */
                if (NOTE_LINE_NUMBER (copy) == NOTE_INSN_EH_REGION_BEG) 
!                 duplicate_eh_handlers (NOTE_BLOCK_NUMBER (copy), new_region,
!                                        save_for_inline_eh_labelmap);
                  
  	      /* We have to forward these both to match the new exception
  		 region.  */
*************** copy_for_inline (orig)
*** 1075,1085 ****
      {
      case QUEUED:
      case CONST_INT:
-     case SYMBOL_REF:
      case PC:
      case CC0:
        return x;
  
      case CONST_DOUBLE:
        /* We have to make a new CONST_DOUBLE to ensure that we account for
  	 it correctly.  Using the old CONST_DOUBLE_MEM data is wrong.  */
--- 1074,1088 ----
      {
      case QUEUED:
      case CONST_INT:
      case PC:
      case CC0:
        return x;
  
+     case SYMBOL_REF:
+       if (! SYMBOL_REF_NEED_ADJUST (x))
+         return x;
+       return rethrow_symbol_map (x, save_for_inline_eh_labelmap);
+ 
      case CONST_DOUBLE:
        /* We have to make a new CONST_DOUBLE to ensure that we account for
  	 it correctly.  Using the old CONST_DOUBLE_MEM data is wrong.  */
*************** process_reg_param (map, loc, copy)
*** 1338,1343 ****
--- 1341,1358 ----
      }
    map->reg_map[REGNO (loc)] = copy;
  }
+ 
+ /* Used by duplicate_eh_handlers to map labels for the exception table */
+ static struct inline_remap *eif_eh_map;
+ 
+ static rtx 
+ expand_inline_function_eh_labelmap (label)
+    rtx label;
+ {
+   int index = CODE_LABEL_NUMBER (label);
+   return get_label_from_map (eif_eh_map, index);
+ }
+ 
  /* Integrate the procedure defined by FNDECL.  Note that this function
     may wind up calling itself.  Since the static variables are not
     reentrant, we do not assign them until after the possibility
*************** expand_inline_function (fndecl, parms, t
*** 2055,2071 ****
                    /* we have to duplicate the handlers for the original */
                    if (NOTE_LINE_NUMBER (copy) == NOTE_INSN_EH_REGION_BEG)
                      {
!                       handler_info *ptr, *temp;
!                       int nr;
!                       nr = new_eh_region_entry (CODE_LABEL_NUMBER (label));
!                       ptr = get_first_handler (NOTE_BLOCK_NUMBER (copy));
!                       for ( ; ptr; ptr = ptr->next)
!                         {
!                           temp = get_new_handler ( get_label_from_map (map, 
!                                       CODE_LABEL_NUMBER (ptr->handler_label)),
!                                                                ptr->type_info);
!                           add_new_handler (nr, temp);
!                         }
                      }
  
  		  /* We have to forward these both to match the new exception
--- 2070,2081 ----
                    /* we have to duplicate the handlers for the original */
                    if (NOTE_LINE_NUMBER (copy) == NOTE_INSN_EH_REGION_BEG)
                      {
!                       /* We need to duplicate the handlers for the EH region
!                          and we need to indicate where the label map is */
!                       eif_eh_map = map;
!                       duplicate_eh_handlers (NOTE_BLOCK_NUMBER (copy), 
!                                              CODE_LABEL_NUMBER (label),
!                                              expand_inline_function_eh_labelmap);
                      }
  
  		  /* We have to forward these both to match the new exception
*************** copy_rtx_and_substitute (orig, map)
*** 2533,2538 ****
--- 2543,2555 ----
  								   map)),
  			 0);
  	}
+       else
+         if (SYMBOL_REF_NEED_ADJUST (orig)) 
+           {
+             eif_eh_map = map;
+             return rethrow_symbol_map (orig, 
+                                        expand_inline_function_eh_labelmap);
+           }
  
        return orig;
  
Index: gcc/libgcc2.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/libgcc2.c,v
retrieving revision 1.54
diff -c -p -r1.54 libgcc2.c
*** libgcc2.c	1998/10/19 19:34:53	1.54
--- libgcc2.c	1998/11/10 15:06:33
*************** old_find_exception_handler (void *pc, ol
*** 3459,3503 ****
    return (void *) 0;
  }
  
  static void *
! find_exception_handler (void *pc, exception_descriptor *table, void *eh_info)
  {
    if (table)
      {
        /* The new model assumed the table is sorted inner-most out so the
           first region we find which matches is the correct one */
  
-       int pos;
-       void *ret;
        exception_table *tab = &(table->table[0]);
  
        /* Subtract 1 from the PC to avoid hitting the next region */
!       pc--;
        
        /* We can't do a binary search because the table is in inner-most
           to outermost address ranges within functions */
!       for (pos = 0; tab[pos].start_region != (void *) -1; pos++)
          { 
            if (tab[pos].start_region <= pc && tab[pos].end_region > pc)
              {
                if (tab[pos].match_info)
                  {
!                   __eh_matcher matcher = ((__eh_info *)eh_info)->match_function;
                    /* match info but no matcher is NOT a match */
                    if (matcher) 
                      {
!                       ret = (*matcher)(eh_info, tab[pos].match_info, table);
!                       if (ret)
!                         return tab[pos].exception_handler;
                      }
                  }
                else
!                 return tab[pos].exception_handler;
              }
          }
      }
! 
!   return (void *) 0;
  }
  #endif /* DWARF2_UNWIND_INFO */
  #endif /* EH_TABLE_LOOKUP */
--- 3459,3540 ----
    return (void *) 0;
  }
  
+ /* find_exception_handler finds the correct handler, if there is one, to
+    handle an exception.
+    returns a pointer to the handler which controlled should be transferred
+    to, or NULL if there is nothing left.
+    Parameters:
+    PC - pc where the exception originates. If this is a rethrow, 
+         then this starts out as a pointer to the exception table
+ 	entry we wish to rethrow out of.
+    TABLE - exception table for the current module.
+    EH_INFO - eh info pointer for this exception.
+    RETHROW - 1 if this is a rethrow. (see incoming value of PC).
+    CLEANUP - returned flag indicating whether this is a cleanup handler.
+ */
  static void *
! find_exception_handler (void *pc, exception_descriptor *table, 
!                         __eh_info *eh_info, int rethrow, int *cleanup)
  {
+ 
+   void *retval = NULL;
+   *cleanup = 1;
    if (table)
      {
+       int pos = 0;
        /* The new model assumed the table is sorted inner-most out so the
           first region we find which matches is the correct one */
  
        exception_table *tab = &(table->table[0]);
  
        /* Subtract 1 from the PC to avoid hitting the next region */
!       if (rethrow) 
!         {
!           /* pc is actually the region table entry to rethrow out of */
!           pos = ((exception_table *) pc) - tab;
!           pc = ((exception_table *) pc)->end_region - 1;
! 
!           /* The label is always on the LAST handler entry for a region, 
!              so we know the next entry is a different region, even if the
!              addresses are the same. Make sure its not end of table tho. */
!           if (tab[pos].start_region != (void *) -1)
!             pos++;
!         }
!       else
!         pc--;
        
        /* We can't do a binary search because the table is in inner-most
           to outermost address ranges within functions */
!       for ( ; tab[pos].start_region != (void *) -1; pos++)
          { 
            if (tab[pos].start_region <= pc && tab[pos].end_region > pc)
              {
                if (tab[pos].match_info)
                  {
!                   __eh_matcher matcher = eh_info->match_function;
                    /* match info but no matcher is NOT a match */
                    if (matcher) 
                      {
!                       void *ret = (*matcher)((void *) eh_info, 
!                                              tab[pos].match_info, table);
!                       if (ret) 
!                         {
!                           if (retval == NULL)
!                             retval = tab[pos].exception_handler;
!                           *cleanup = 0;
!                           break;
!                         }
                      }
                  }
                else
!                 {
!                   if (retval == NULL)
!                     retval = tab[pos].exception_handler;
!                 }
              }
          }
      }
!   return retval;
  }
  #endif /* DWARF2_UNWIND_INFO */
  #endif /* EH_TABLE_LOOKUP */
*************** next_stack_level (void *pc, frame_state 
*** 3633,3687 ****
  
    return caller_udata;
  }
- 
- /* We first search for an exception handler, and if we don't find
-    it, we call __terminate on the current stack frame so that we may
-    use the debugger to walk the stack and understand why no handler
-    was found.
- 
-    If we find one, then we unwind the frames down to the one that
-    has the handler and transfer control into the handler.  */
  
! /*extern void __throw(void) __attribute__ ((__noreturn__));*/
! 
! void
! __throw ()
  {
!   struct eh_context *eh = (*get_eh_context) ();
!   void *saved_pc, *pc, *handler;
!   frame_state ustruct, ustruct2;
!   frame_state *udata = &ustruct;
!   frame_state *sub_udata = &ustruct2;
!   frame_state my_ustruct, *my_udata = &my_ustruct;
!   long args_size;
!   int new_exception_model;
! 
!   /* This is required for C++ semantics.  We must call terminate if we
!      try and rethrow an exception, when there is no exception currently
!      active.  */
!   if (! eh->info)
!     __terminate ();
!     
!   /* Start at our stack frame.  */
! label:
!   udata = __frame_state_for (&&label, udata);
!   if (! udata)
!     __terminate ();
! 
!   /* We need to get the value from the CFA register. */
!   udata->cfa = __builtin_dwarf_cfa ();
  
!   memcpy (my_udata, udata, sizeof (*udata));
  
!   /* Do any necessary initialization to access arbitrary stack frames.
!      On the SPARC, this means flushing the register windows.  */
!   __builtin_unwind_init ();
! 
!   /* Now reset pc to the right throw point.  */
!   pc = __builtin_extract_return_addr (__builtin_return_address (0)) - 1;
!   saved_pc = pc;
  
!   handler = 0;
    for (;;)
      { 
        frame_state *p = udata;
--- 3670,3717 ----
  
    return caller_udata;
  }
  
! /* Hook to call before __terminate if only cleanup handlers remain. */
! void 
! __unwinding_cleanup ()
  {
! }
  
! /* throw_helper performs some of the common grunt work for a throw. This
!    routine is called by throw and rethrows. This is pretty much split 
!    out from the old __throw routine. An addition has been added which allows
!    for a dummy call to a routine __unwinding_cleanup() when there are nothing
!    but cleanups remaining. This allows a debugger to examine the state
!    at which the throw was executed, before any cleanups, rather than
!    at the terminate point after the stack has been unwound. */
  
! static void *
! throw_helper (eh, pc, my_udata, udata_p)
!      struct eh_context *eh;
!      void *pc;
!      frame_state *my_udata;
!      frame_state **udata_p;
! {
!   frame_state *udata = *udata_p;
!   frame_state ustruct;
!   frame_state *sub_udata = &ustruct;
!   void *saved_pc = pc;
!   void *handler;
!   void *handler_p;
!   void *pc_p;
!   frame_state saved_ustruct;
!   int new_eh_model;
!   int cleanup = 0;
!   int only_cleanup = 0;
!   int rethrow = 0;
!   int saved_state = 0;
!   __eh_info *eh_info = (__eh_info *)eh->info;
! 
!   /* Do we find a handler based on a re-throw PC? */
!   if (eh->table_index != (void *) 0)
!     rethrow = 1;
  
!   handler = (void *) 0;
    for (;;)
      { 
        frame_state *p = udata;
*************** label:
*** 3693,3724 ****
  	break;
  
        if (udata->eh_ptr == NULL)
!         new_exception_model = 0;
        else
!         new_exception_model = (((exception_descriptor *)(udata->eh_ptr))->
                                            runtime_id_field == NEW_EH_RUNTIME);
  
!       if (new_exception_model)
!         handler = find_exception_handler (pc, udata->eh_ptr, eh->info);
        else
!         handler = old_find_exception_handler (pc, udata->eh_ptr);
! 
!       /* If we found one, we can stop searching.  */
        if (handler)
! 	{
! 	  args_size = udata->args_size;
! 	  break;
! 	}
  
        /* Otherwise, we continue searching.  We subtract 1 from PC to avoid
  	 hitting the beginning of the next region.  */
        pc = get_return_addr (udata, sub_udata) - 1;
      }
  
    /* If we haven't found a handler by now, this is an unhandled
       exception.  */
!   if (! handler)
!     __terminate ();
  
    eh->handler_label = handler;
  
--- 3723,3786 ----
  	break;
  
        if (udata->eh_ptr == NULL)
!         new_eh_model = 0;
        else
!         new_eh_model = (((exception_descriptor *)(udata->eh_ptr))->
                                            runtime_id_field == NEW_EH_RUNTIME);
  
!       if (rethrow) 
!         {
!           rethrow = 0;
!           handler = find_exception_handler (eh->table_index, udata->eh_ptr, 
!                                           eh_info, 1, &cleanup);
!           eh->table_index = (void *)0;
!         }
        else
!         if (new_eh_model)
!           handler = find_exception_handler (pc, udata->eh_ptr, eh_info, 
!                                             0, &cleanup);
!         else
!           handler = old_find_exception_handler (pc, udata->eh_ptr);
! 
!       /* If we found one, we can stop searching, if its not a cleanup. 
!          for cleanups, we save the state, and keep looking. This allows
!          us to call a debug hook if there are nothing but cleanups left. */
        if (handler)
! 	if (cleanup)
! 	  {
! 	    if (!saved_state)
! 	      {
! 		saved_ustruct = *udata;
! 		handler_p = handler;
! 		pc_p = pc;
! 		saved_state = 1;
! 		only_cleanup = 1;
! 	      }
! 	  }
! 	else
! 	  {
! 	    only_cleanup = 0;
! 	    break;
! 	  }
  
        /* Otherwise, we continue searching.  We subtract 1 from PC to avoid
  	 hitting the beginning of the next region.  */
        pc = get_return_addr (udata, sub_udata) - 1;
      }
  
+   if (saved_state) 
+     {
+       udata = &saved_ustruct;
+       handler = handler_p;
+       pc = pc_p;
+       if (only_cleanup)
+         __unwinding_cleanup ();
+     }
+ 
    /* If we haven't found a handler by now, this is an unhandled
       exception.  */
!   if (! handler) 
!     __terminate();
  
    eh->handler_label = handler;
  
*************** label:
*** 3772,3777 ****
--- 3834,3947 ----
  	    copy_reg (i, udata, my_udata);
  	}
      }
+   /* udata now refers to the frame called by the handler frame.  */
+ 
+   *udata_p = udata;
+   return handler;
+ }
+ 
+ 
+ /* We first search for an exception handler, and if we don't find
+    it, we call __terminate on the current stack frame so that we may
+    use the debugger to walk the stack and understand why no handler
+    was found.
+ 
+    If we find one, then we unwind the frames down to the one that
+    has the handler and transfer control into the handler.  */
+ 
+ /*extern void __throw(void) __attribute__ ((__noreturn__));*/
+ 
+ void
+ __throw ()
+ {
+   struct eh_context *eh = (*get_eh_context) ();
+   void *pc, *handler;
+   frame_state ustruct;
+   frame_state *udata = &ustruct;
+   frame_state my_ustruct, *my_udata = &my_ustruct;
+ 
+   /* This is required for C++ semantics.  We must call terminate if we
+      try and rethrow an exception, when there is no exception currently
+      active.  */
+   if (! eh->info)
+     __terminate ();
+     
+   /* Start at our stack frame.  */
+ label:
+   udata = __frame_state_for (&&label, udata);
+   if (! udata)
+     __terminate ();
+ 
+   /* We need to get the value from the CFA register. */
+   udata->cfa = __builtin_dwarf_cfa ();
+ 
+   memcpy (my_udata, udata, sizeof (*udata));
+ 
+   /* Do any necessary initialization to access arbitrary stack frames.
+      On the SPARC, this means flushing the register windows.  */
+   __builtin_unwind_init ();
+ 
+   /* Now reset pc to the right throw point.  */
+   pc = __builtin_extract_return_addr (__builtin_return_address (0)) - 1;
+ 
+   handler = throw_helper (eh, pc, my_udata, &udata);
+ 
+   /* Now go!  */
+ 
+   __builtin_eh_return ((void *)eh,
+ #ifdef STACK_GROWS_DOWNWARD
+ 		       udata->cfa - my_udata->cfa,
+ #else
+ 		       my_udata->cfa - udata->cfa,
+ #endif
+ 		       handler);
+ 
+   /* Epilogue:  restore the handler frame's register values and return
+      to the stub.  */
+ }
+ 
+ /*extern void __rethrow(void *) __attribute__ ((__noreturn__));*/
+ 
+ void
+ __rethrow (index)
+      void *index;
+ {
+   struct eh_context *eh = (*get_eh_context) ();
+   void *pc, *handler;
+   frame_state ustruct;
+   frame_state *udata = &ustruct;
+   frame_state my_ustruct, *my_udata = &my_ustruct;
+ 
+   /* This is required for C++ semantics.  We must call terminate if we
+      try and rethrow an exception, when there is no exception currently
+      active.  */
+   if (! eh->info)
+     __terminate ();
+ 
+   /* This is the table index we want to rethrow from. The value of
+      the END_REGION label is used for the PC of the throw, and the
+      search begins with the next table entry. */
+   eh->table_index = index;
+     
+   /* Start at our stack frame.  */
+ label:
+   udata = __frame_state_for (&&label, udata);
+   if (! udata)
+     __terminate ();
+ 
+   /* We need to get the value from the CFA register. */
+   udata->cfa = __builtin_dwarf_cfa ();
+ 
+   memcpy (my_udata, udata, sizeof (*udata));
+ 
+   /* Do any necessary initialization to access arbitrary stack frames.
+      On the SPARC, this means flushing the register windows.  */
+   __builtin_unwind_init ();
+ 
+   /* Now reset pc to the right throw point.  */
+   pc = __builtin_extract_return_addr (__builtin_return_address (0)) - 1;
+ 
+   handler = throw_helper (eh, pc, my_udata, &udata);
  
    /* Now go!  */
  
Index: gcc/cp/except.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/except.c,v
retrieving revision 1.54
diff -c -p -r1.54 except.c
*** except.c	1998/10/26 23:48:55	1.54
--- except.c	1998/11/10 15:06:34
*************** call_eh_info ()
*** 249,262 ****
  {
    tree fn;
  
!   fn = get_identifier ("__cp_eh_info");
    if (IDENTIFIER_GLOBAL_VALUE (fn))
      fn = IDENTIFIER_GLOBAL_VALUE (fn);
    else
      {
        tree t1, t, fields[7];
  
!       /* Declare cp_eh_info * __cp_eh_info (void),
  	 as defined in exception.cc. */
        push_obstacks_nochange ();
        end_temporary_allocation ();
--- 249,262 ----
  {
    tree fn;
  
!   fn = get_identifier ("__start_cp_handler");
    if (IDENTIFIER_GLOBAL_VALUE (fn))
      fn = IDENTIFIER_GLOBAL_VALUE (fn);
    else
      {
        tree t1, t, fields[7];
  
!       /* Declare cp_eh_info * __start_cp_handler (void),
  	 as defined in exception.cc. */
        push_obstacks_nochange ();
        end_temporary_allocation ();
*************** call_eh_info ()
*** 270,278 ****
                      get_identifier ("dynamic_handler_chain"), ptr_type_node);
        fields[2] = build_lang_field_decl (FIELD_DECL, 
                      get_identifier ("info"), ptr_type_node);
        /* N.B.: The fourth field LEN is expected to be
  	 the number of fields - 1, not the total number of fields.  */
!       finish_builtin_type (t1, "eh_context", fields, 2, ptr_type_node);
        t1 = build_pointer_type (t1);
  
        t1= make_lang_type (RECORD_TYPE);
--- 270,280 ----
                      get_identifier ("dynamic_handler_chain"), ptr_type_node);
        fields[2] = build_lang_field_decl (FIELD_DECL, 
                      get_identifier ("info"), ptr_type_node);
+       fields[3] = build_lang_field_decl (FIELD_DECL, 
+                     get_identifier ("table_index"), ptr_type_node);
        /* N.B.: The fourth field LEN is expected to be
  	 the number of fields - 1, not the total number of fields.  */
!       finish_builtin_type (t1, "eh_context", fields, 3, ptr_type_node);
        t1 = build_pointer_type (t1);
  
        t1= make_lang_type (RECORD_TYPE);
*************** push_eh_cleanup ()
*** 549,557 ****
  {
    int yes;
  
-   expand_expr (build_unary_op (PREINCREMENT_EXPR, get_eh_handlers (), 1),
- 	       const0_rtx, VOIDmode, EXPAND_NORMAL);
- 
    yes = suspend_momentary ();
    /* All cleanups must last longer than normal.  */
    expand_decl_cleanup (NULL_TREE, do_pop_exception ());
--- 551,556 ----
*************** process_start_catch_block (declspecs, de
*** 701,709 ****
  
        /* Fall into the catch all section.  */
      }
- 
-   init = build_modify_expr (get_eh_caught (), NOP_EXPR, integer_one_node);
-   expand_expr (init, const0_rtx, VOIDmode, EXPAND_NORMAL);
  
    emit_line_note (input_filename, lineno);
  }
--- 700,705 ----
Index: gcc/cp/exception.cc
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/exception.cc,v
retrieving revision 1.19
diff -c -p -r1.19 exception.cc
*** exception.cc	1998/10/23 16:26:19	1.19
--- exception.cc	1998/11/10 15:06:35
*************** __cp_exception_info (void)
*** 116,128 ****
    return &((*__get_eh_info ())->value);
  }
  
! /* Compiler hook to return a pointer to the info for the current exception.
     Used by get_eh_info ().  */
  
  extern "C" cp_eh_info *
  __cp_eh_info (void)
  {
!   return *__get_eh_info ();
  }
  
  /* Allocate a buffer for a cp_eh_info and an exception object of size SIZE,
--- 116,144 ----
    return &((*__get_eh_info ())->value);
  }
  
! #define CP_EH_INFO ((cp_eh_info *) *__get_eh_info ())
! 
! /* Old Compiler hook to return a pointer to the info for the current exception.
     Used by get_eh_info ().  */
  
  extern "C" cp_eh_info *
  __cp_eh_info (void)
+ {
+   cp_eh_info *p = CP_EH_INFO;
+   return p;
+ }
+ 
+ /* Compiler hook to return a pointer to the info for the current exception,
+    Set the caught bit, and increment the number of handlers that are
+    looking at this exception. This makes handlers smaller. */
+ 
+ extern "C" cp_eh_info *
+ __start_cp_handler (void)
  {
!   cp_eh_info *p = CP_EH_INFO;
!   p->caught = 1;
!   p->handlers++;
!   return p;
  }
  
  /* Allocate a buffer for a cp_eh_info and an exception object of size SIZE,
*************** __cp_pop_exception (cp_eh_info *p)
*** 241,247 ****
  extern "C" void
  __uncatch_exception (void)
  {
!   cp_eh_info *p = __cp_eh_info ();
    if (p == 0)
      terminate ();
    p->caught = false;
--- 257,263 ----
  extern "C" void
  __uncatch_exception (void)
  {
!   cp_eh_info *p = CP_EH_INFO;
    if (p == 0)
      terminate ();
    p->caught = false;
*************** __uncatch_exception (void)
*** 262,268 ****
  extern "C" void
  __check_eh_spec (int n, const void **spec)
  {
!   cp_eh_info *p = __cp_eh_info ();
  
    for (int i = 0; i < n; ++i)
      {
--- 278,284 ----
  extern "C" void
  __check_eh_spec (int n, const void **spec)
  {
!   cp_eh_info *p = CP_EH_INFO;
  
    for (int i = 0; i < n; ++i)
      {
*************** __throw_bad_typeid (void)
*** 315,321 ****
  bool
  std::uncaught_exception ()
  {
!   cp_eh_info *p = __cp_eh_info ();
    return p && ! p->caught;
  }
  
--- 331,337 ----
  bool
  std::uncaught_exception ()
  {
!   cp_eh_info *p = CP_EH_INFO;
    return p && ! p->caught;
  }
  



More information about the Gcc-patches mailing list