eh patch

Andrew Macleod amacleod@cygnus.com
Tue Sep 15 11:30:00 GMT 1998


The following patch has been applied to egcs as part of the effort to 
unify the exception handling interface (new/old/sjlj). No one should notice 
any difference (hopefully!), except the front end no longer needs to understand 
the flag  flag_new_exceptions as it use to.
  The front end mechanism for exception regions now looks something like:

  start_try_block ()
  start_catch_block ()
  for each handler in try block
    {
      start_catch_handler (type_match)
      end_catch_handler ();
    }
  end_catch_block ()

And its transparent whether a handler has its own entry in the exception
table (-fnew-exceptions), one handler contains compares and branch around code
for each run-time possibility (-fexceptions) or one handler and 
runtime compares using setjmp/longjmp (-fsjlj-exceptions).

If anyone experiences problems, let me know ASAP. 

Thanks
Andrew

Index: ChangeLog
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/ChangeLog,v
retrieving revision 1.2077
diff -c -p -r1.2077 ChangeLog
*** ChangeLog	1998/09/15 11:02:57	1.2077
--- ChangeLog	1998/09/15 18:14:54
***************
*** 1,3 ****
--- 1,18 ----
+ Tue Sep 15 14:10:54 EDT 1998  Andrew MacLeod  <amacleod@cygnus.com>
+ 
+ 	* except.h (struct eh_entry): Add false_label field.
+ 	(end_catch_handler): Add prototype.
+ 	* except.c (push_eh_entry): Set false_label field to NULL_RTX.
+ 	(start_catch_handler): When using old style exceptions, issue
+ 	runtime typematch code before continuing with the handler.
+ 	(end_catch_handler): New function, generates label after handler
+ 	if needed by older style exceptions.
+ 	(expand_start_all_catch): No need to check for new style exceptions.
+ 	(output_exception_table_entry): Only output the first handler label
+ 	for old style exceptions.
+ 	* libgcc2.c (__eh_rtime_match): New routine to lump runtime matching
+ 	mechanism into one function, if a runtime matcher is provided.
+ 
  Tue Sep 15 13:53:59 EDT 1998  Andrew MacLeod  <amacleod@cygnus.com>
  
  	* config/i960/i960.h (SLOW_BYTE_ACCESS): Change definition to 1.
Index: except.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/except.c,v
retrieving revision 1.63
diff -c -p -r1.63 except.c
*** except.c	1998/09/09 21:48:40	1.63
--- except.c	1998/09/15 18:14:57
*************** push_eh_entry (stack)
*** 597,602 ****
--- 597,603 ----
    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;
*************** start_catch_handler (rtime)
*** 1600,1605 ****
--- 1601,1654 ----
    receive_exception_label (handler_label);
  
    add_new_handler (eh_region_entry, get_new_handler (handler_label, rtime));
+ 
+   if (flag_new_exceptions && ! exceptions_via_longjmp)
+     return;
+ 
+   /* Under the old mechanism, as well as setjmp/longjmp, we need to
+      issue code to compare 'rtime' to the value in eh_info, via the
+      matching function in eh_info. If its is false, we branch around
+      the handler we are about to issue. */
+ 
+   if (rtime != NULL_TREE && rtime != CATCH_ALL_TYPE)
+     {
+       rtx call_rtx, rtime_address;
+ 
+       if (catchstack.top->entry->false_label != NULL_RTX)
+         error ("never issued previous false_label");
+       catchstack.top->entry->false_label = gen_exception_label ();
+ 
+       rtime_address = expand_expr (rtime, NULL_RTX, Pmode, EXPAND_INITIALIZER);
+       rtime_address = force_reg (Pmode, rtime_address);
+ 
+       /* Now issue the call, and branch around handler if needed */
+       call_rtx = emit_library_call_value (
+         gen_rtx_SYMBOL_REF (Pmode, "__eh_rtime_match"), NULL_RTX, 
+                                         0, SImode, 1, rtime_address, Pmode);
+ 
+       /* Did the function return true? */
+       emit_cmp_insn (call_rtx, const0_rtx, EQ, NULL_RTX,
+                                                 GET_MODE (call_rtx), 0 ,0);
+       emit_jump_insn (gen_beq (catchstack.top->entry->false_label));
+     }
+ }
+ 
+ /* Called to end a catch clause. If we aren't using the new exception
+    model tabel mechanism, we need to issue the branch-around label
+    for the end of the catch block. */
+ 
+ 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)
+     return;
+ 
+   emit_label (catchstack.top->entry->false_label);
+   catchstack.top->entry->false_label = NULL_RTX;
  }
  
  /* Generate RTL for the start of a group of catch clauses. 
*************** expand_start_all_catch ()
*** 1693,1701 ****
        ehstack.top->entry->outer_context = outer_context;
      }
  
-   /* We also have to start the handler if we aren't using the new model. */
-   if (! flag_new_exceptions)
-     start_catch_handler (NULL);
  }
  
  /* Finish up the catch block.  At this point all the insns for the
--- 1742,1747 ----
*************** output_exception_table_entry (file, n)
*** 1927,1932 ****
--- 1973,1981 ----
                                                  POINTER_SIZE / BITS_PER_UNIT);
          }
        putc ('\n', file);		/* blank line */
+       /* We only output the first label under the old scheme */
+       if (! flag_new_exceptions)
+         break;
      }
  }
  
Index: except.h
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/except.h,v
retrieving revision 1.22
diff -c -p -r1.22 except.h
*** except.h	1998/09/09 21:48:39	1.22
--- except.h	1998/09/15 18:14:58
*************** struct label_node {
*** 53,58 ****
--- 53,62 ----
     label or not. New ones are needed for additional catch blocks if
     it has.
  
+    FALSE_LABEL is used when either setjmp/longjmp exceptions are in
+    use, or old style table exceptions. It contains the label for 
+    branching to the next runtime type check as handlers are processed.
+ 
     FINALIZATION is the tree codes for the handler, or is NULL_TREE if
     one hasn't been generated yet, or is integer_zero_node to mark the
     end of a group of try blocks.  */
*************** struct eh_entry {
*** 62,67 ****
--- 66,72 ----
    rtx exception_handler_label;
    tree finalization;
    int label_used;
+   rtx false_label;
  };
  
  /* A list of EH_ENTRYs. ENTRY is the entry; CHAIN points to the next
*************** extern void add_eh_table_entry			PROTO((
*** 236,241 ****
--- 241,250 ----
  #ifdef TREE_CODE
  extern void start_catch_handler                 PROTO((tree));
  #endif
+ 
+ /* End an individual catch clause. */
+ 
+ extern void end_catch_handler                   PROTO((void));
  
  /* Returns a non-zero value if we need to output an exception table.  */
  
Index: libgcc2.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/libgcc2.c,v
retrieving revision 1.46
diff -c -p -r1.46 libgcc2.c
*** libgcc2.c	1998/07/06 23:52:21	1.46
--- libgcc2.c	1998/09/15 18:15:00
*************** __sjpopnthrow ()
*** 3355,3360 ****
--- 3355,3375 ----
  
  /* Support code for all exception region-based exception handling.  */
  
+ int
+ __eh_rtime_match (void *rtime)
+ {
+   void *info;
+   __eh_matcher matcher;
+   void *ret;
+ 
+   info = *(__get_eh_info ());
+   matcher = ((__eh_info *)info)->match_function;
+   if (!matcher)
+     perror ("No runtime type matcher available");
+   ret = (*matcher) (info, rtime, (void *)0);
+   return ((int)ret);
+ }
+ 
  /* This value identifies the place from which an exception is being
     thrown.  */
  
Index: cp/ChangeLog
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/ChangeLog,v
retrieving revision 1.678
diff -c -p -r1.678 ChangeLog
*** ChangeLog	1998/09/15 11:03:01	1.678
--- ChangeLog	1998/09/15 18:15:16
***************
*** 1,5 ****
--- 1,15 ----
  1998-09-15  Andrew MacLeod  <amacleod@cygnus.com>
  
+ 	* except.c (expand_start_catch_block): No need to check for new
+ 	exception model.
+ 	(process_start_catch_block_old): Deleted.
+ 	(process_start_catch_block): Add call to start_decl_1().
+ 	(expand_end_catch_block): Add call to end_catch_handler().
+ 	* exception.cc (__cplus_type_matcher): Only check the exception 
+ 	language if there is an exception table.
+ 
+ 1998-09-15  Andrew MacLeod  <amacleod@cygnus.com>
+ 
  	* search.c (expand_indirect_vtbls_init): Mark temporary stack slots
  	as used to prevent conflicts with virtual function tables.
  
Index: cp/except.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/except.c,v
retrieving revision 1.51
diff -c -p -r1.51 except.c
*** except.c	1998/09/07 14:25:06	1.51
--- except.c	1998/09/15 18:15:18
*************** expand_start_catch_block (declspecs, dec
*** 597,731 ****
    if (! doing_eh (1))
      return;
  
!   if (flag_new_exceptions)
!     process_start_catch_block (declspecs, declarator);
!   else
!     process_start_catch_block_old (declspecs, declarator);
  }
  
  
  /* This function performs the expand_start_catch_block functionality for 
-    exceptions implemented in the old style, where catch blocks were all
-    called, and had to check the runtime information themselves. */
- 
- static void 
- process_start_catch_block_old (declspecs, declarator)
-      tree declspecs, declarator;
- {
-   rtx false_label_rtx;
-   tree decl = NULL_TREE;
-   tree init;
- 
-   /* Create a binding level for the eh_info and the exception object
-      cleanup.  */
-   pushlevel (0);
-   expand_start_bindings (0);
- 
-   false_label_rtx = gen_label_rtx ();
-   push_label_entry (&false_label_stack, false_label_rtx, NULL_TREE);
- 
-   emit_line_note (input_filename, lineno);
- 
-   push_eh_info ();
- 
-   if (declspecs)
-     {
-       decl = grokdeclarator (declarator, declspecs, CATCHPARM, 1, NULL_TREE);
- 
-       if (decl == NULL_TREE)
- 	error ("invalid catch parameter");
-     }
- 
-   if (decl)
-     {
-       tree exp;
-       rtx call_rtx, return_value_rtx;
-       tree init_type;
- 
-       /* Make sure we mark the catch param as used, otherwise we'll get
- 	 a warning about an unused ((anonymous)).  */
-       TREE_USED (decl) = 1;
- 
-       /* Figure out the type that the initializer is.  */
-       init_type = TREE_TYPE (decl);
-       if (TREE_CODE (init_type) != REFERENCE_TYPE
- 	  && TREE_CODE (init_type) != POINTER_TYPE)
- 	init_type = build_reference_type (init_type);
- 
-       exp = get_eh_value ();
- 
-       /* Since pointers are passed by value, initialize a reference to
- 	 pointer catch parm with the address of the value slot.  */
-       if (TREE_CODE (init_type) == REFERENCE_TYPE
- 	  && TREE_CODE (TREE_TYPE (init_type)) == POINTER_TYPE)
- 	exp = build_unary_op (ADDR_EXPR, exp, 1);
- 
-       exp = expr_tree_cons (NULL_TREE,
- 		       build_eh_type_type (TREE_TYPE (decl)),
- 		       expr_tree_cons (NULL_TREE,
- 				  get_eh_type (),
- 				  expr_tree_cons (NULL_TREE, exp, NULL_TREE)));
-       exp = build_function_call (CatchMatch, exp);
-       call_rtx = expand_call (exp, NULL_RTX, 0);
- 
-       return_value_rtx = hard_function_value (ptr_type_node, exp);
- 
-       /* did the throw type match function return TRUE? */
-       emit_cmp_insn (return_value_rtx, const0_rtx, EQ, NULL_RTX,
- 		    GET_MODE (return_value_rtx), 0, 0);
- 
-       /* if it returned FALSE, jump over the catch block, else fall into it */
-       emit_jump_insn (gen_beq (false_label_rtx));
- 
-       push_eh_cleanup ();
- 
-       /* Create a binding level for the parm.  */
-       pushlevel (0);
-       expand_start_bindings (0);
- 
-       init = convert_from_reference (make_tree (init_type, call_rtx));
- 
-       /* If the constructor for the catch parm exits via an exception, we
-          must call terminate.  See eh23.C.  */
-       if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl)))
- 	{
- 	  /* Generate the copy constructor call directly so we can wrap it.
- 	     See also expand_default_init.  */
- 	  init = ocp_convert (TREE_TYPE (decl), init,
- 			      CONV_IMPLICIT|CONV_FORCE_TEMP, 0);
- 	  init = build (TRY_CATCH_EXPR, TREE_TYPE (init), init,
- 			build_terminate_handler ());
- 	}
- 
-       /* Let `cp_finish_decl' know that this initializer is ok.  */
-       DECL_INITIAL (decl) = init;
-       decl = pushdecl (decl);
- 
-       start_decl_1 (decl);
-       cp_finish_decl (decl, DECL_INITIAL (decl),
- 		      NULL_TREE, 0, LOOKUP_ONLYCONVERTING);
-     }
-   else
-     {
-       push_eh_cleanup ();
- 
-       /* Create a binding level for the parm.  */
-       pushlevel (0);
-       expand_start_bindings (0);
- 
-       /* 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);
- }
- 
- /* This function performs the expand_start_catch_block functionality for 
     exceptions implemented in the new style. __throw determines whether
     a handler needs to be called or not, so the handler itself has to do
!    nothing additionaal. */
  
  static void 
  process_start_catch_block (declspecs, declarator)
--- 597,610 ----
    if (! doing_eh (1))
      return;
  
!   process_start_catch_block (declspecs, declarator);
  }
  
  
  /* This function performs the expand_start_catch_block functionality for 
     exceptions implemented in the new style. __throw determines whether
     a handler needs to be called or not, so the handler itself has to do
!    nothing additional. */
  
  static void 
  process_start_catch_block (declspecs, declarator)
*************** process_start_catch_block (declspecs, de
*** 806,811 ****
--- 685,691 ----
        DECL_INITIAL (decl) = init;
        decl = pushdecl (decl);
  
+       start_decl_1 (decl);
        cp_finish_decl (decl, init, NULL_TREE, 0, LOOKUP_ONLYCONVERTING);
      }
    else
*************** expand_end_catch_block ()
*** 849,858 ****
       documentation.  */
    expand_goto (top_label_entry (&caught_return_label_stack));
  
!   /* label we emit to jump to if this catch block didn't match.  */
!   /* This the closing } in the `if (eq) {' of the documentation.  */
!   if (! flag_new_exceptions)
!     emit_label (pop_label_entry (&false_label_stack));
  }
  
  /* An exception spec is implemented more or less like:
--- 729,735 ----
       documentation.  */
    expand_goto (top_label_entry (&caught_return_label_stack));
  
!   end_catch_handler ();
  }
  
  /* An exception spec is implemented more or less like:
Index: cp/exception.cc
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/exception.cc,v
retrieving revision 1.16
diff -c -p -r1.16 exception.cc
*** exception.cc	1998/06/25 14:11:53	1.16
--- exception.cc	1998/09/15 18:15:18
*************** __cplus_type_matcher (cp_eh_info *info, 
*** 157,163 ****
  {
    void *ret;
  
!   if (exception_table->lang.language != EH_LANG_C_plus_plus)
      return NULL;
  
    if (match_info == CATCH_ALL_TYPE)
--- 157,165 ----
  {
    void *ret;
  
!   /* No exception table implies the old style mechanism, so don't check. */
!   if (exception_table != NULL && 
!                         exception_table->lang.language != EH_LANG_C_plus_plus)
      return NULL;
  
    if (match_info == CATCH_ALL_TYPE)



More information about the Gcc-patches mailing list