This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Add support for a TREE_LIST of types to expand_start_catch



Hello,

This is a followup to a discussion from a while ago :

   http://gcc.gnu.org/ml/gcc/2001-06/msg01009.html

Here is the context summarized :

  I wrote :
  > We are making experiments to use the GCC (cvs trunk) framework for EH in
  > GNAT and already have had some encouraging results :) A basic question
  > comes up in this context :

  > What kind of argument should we provide to expand_start_catch when a
  > single handler is in place for several exceptions ?

  Richard Henderson replied :
  > A TREE_LIST, though that is not directly supported by the code now.

The patch below is an attempt at providing the missing support. As I am not
very experienced with GCC development, there might be better ways to achieve
the intention and I am of course very interested in comments on how this could
be improved.

Olivier


Testing
-------

Successfully bootstrapped and regression tested for c, c++ on
i686-pc-linux-gnu. Also basically tested for functionality on a couple
of Ada testcases.

ChangeLog
---------

2001-11-15  Olivier Hainque <hainque@act-europe.fr>

        * except.c: Support for catching a list of types with a single handler
        (struct eh_region): Change type and filter to lists for catch regions.
        (mark_eh_region): Mark the filter list for GC also.
        (expand_start_catch): Always build a list if argument not NULL and
        register each type of the list through add_type_for_runtime.
        (duplicate_eh_region_1): Change type into type_list for catch regions.
        (assign_filter_values): Assign a filter to each type associated with a
        catch region. Assign filter for NULL types in a unique entry in the
        filter list.
        (build_post_landing_pads): Emit compare and jump for each filter of
        the list associated with a catch region.
        (reachable_next_level): When the type thrown is known, stop the search
        as soon as one type within a catch list matches. Also, a handler is
        potentially reachable only if at least one of the types it catches
        has not been previously caught.
        (collect_one_action_chain): Retrieve the filter for a NULL type list
        from the first filter list entry. For non NULL type lists, add an
        action record for every filter assigned.

        * except.h: Reflect changes in comment before expand_start_catch.

Patch
-----

*** except.c.ori	Thu Nov 15 10:05:52 2001
--- except.c	Thu Nov 15 15:57:31 2001
*************** struct eh_region
*** 148,160 ****
        rtx continue_label;
      } try;
  
!     /* The list through the catch handlers, the type object
!        matched, and a pointer to the generated code.  */
      struct {
        struct eh_region *next_catch;
        struct eh_region *prev_catch;
!       tree type;
!       int filter;
      } catch;
  
      /* A tree_list of allowed types.  */
--- 148,160 ----
        rtx continue_label;
      } try;
  
!     /* The list through the catch handlers, the list of type objects
!        matched, and the list of associated filters.  */
      struct {
        struct eh_region *next_catch;
        struct eh_region *prev_catch;
!       tree type_list;
!       tree filter_list;
      } catch;
  
      /* A tree_list of allowed types.  */
*************** mark_eh_region (region)
*** 485,491 ****
        ggc_mark_rtx (region->u.try.continue_label);
        break;
      case ERT_CATCH:
!       ggc_mark_tree (region->u.catch.type);
        break;
      case ERT_ALLOWED_EXCEPTIONS:
        ggc_mark_tree (region->u.allowed.type_list);
--- 485,492 ----
        ggc_mark_rtx (region->u.try.continue_label);
        break;
      case ERT_CATCH:
!       ggc_mark_tree (region->u.catch.type_list);
!       ggc_mark_tree (region->u.catch.filter_list);
        break;
      case ERT_ALLOWED_EXCEPTIONS:
        ggc_mark_tree (region->u.allowed.type_list);
*************** expand_start_all_catch ()
*** 767,792 ****
    emit_jump (region->u.try.continue_label);
  }
  
! /* Begin a catch clause.  TYPE is the type caught, or null if this is
!    a catch-all clause.  */
  
  void
! expand_start_catch (type)
!      tree type;
  {
    struct eh_region *t, *c, *l;
  
    if (! doing_eh (0))
      return;
  
!   if (type)
!     add_type_for_runtime (type);
    expand_eh_region_start ();
  
    t = cfun->eh->try_region;
    c = cfun->eh->cur_region;
    c->type = ERT_CATCH;
!   c->u.catch.type = type;
    c->label = gen_label_rtx ();
  
    l = t->u.try.last_catch;
--- 768,811 ----
    emit_jump (region->u.try.continue_label);
  }
  
! /* Begin a catch clause.  TYPE is the type caught, a list of such types, or
!    null if this is a catch-all clause. Providing a type list enables to
!    associate the catch region with potentially several exception types, which
!    is useful e.g. for Ada. */
  
  void
! expand_start_catch (type_or_list)
!      tree type_or_list;
  {
    struct eh_region *t, *c, *l;
+   tree type_list;
  
    if (! doing_eh (0))
      return;
  
!   type_list = type_or_list;
! 
!   if (type_or_list)
!     {
!       /* Ensure to always end up with a type list to normalize further
!          processing, then register each type against the runtime types
!          map.  */
!       tree type_node;
! 
!       if (TREE_CODE (type_or_list) != TREE_LIST)
!         type_list = tree_cons (NULL_TREE, type_or_list, NULL_TREE);
! 
!       type_node = type_list;
!       for (; type_node; type_node = TREE_CHAIN (type_node))
!         add_type_for_runtime (TREE_VALUE (type_node));
!     }
! 
    expand_eh_region_start ();
  
    t = cfun->eh->try_region;
    c = cfun->eh->cur_region;
    c->type = ERT_CATCH;
!   c->u.catch.type_list = type_list;
    c->label = gen_label_rtx ();
  
    l = t->u.try.last_catch;
*************** duplicate_eh_region_1 (o, map)
*** 1348,1354 ****
        break;
  
      case ERT_CATCH:
!       n->u.catch.type = o->u.catch.type;
        break;
  
      case ERT_ALLOWED_EXCEPTIONS:
--- 1367,1373 ----
        break;
  
      case ERT_CATCH:
!       n->u.catch.type_list = o->u.catch.type_list;
        break;
  
      case ERT_ALLOWED_EXCEPTIONS:
*************** assign_filter_values ()
*** 1693,1699 ****
        switch (r->type)
  	{
  	case ERT_CATCH:
! 	  r->u.catch.filter = add_ttypes_entry (ttypes, r->u.catch.type);
  	  break;
  
  	case ERT_ALLOWED_EXCEPTIONS:
--- 1712,1747 ----
        switch (r->type)
  	{
  	case ERT_CATCH:
! 	  /* Whatever type_list is (NULL or true list), we build a list
! 	     of filters for the region.  */
! 	  r->u.catch.filter_list = NULL_TREE;
! 
! 	  if (r->u.catch.type_list != NULL)
! 	    {
! 	      /* Get a filter value for each of the types caught and store
! 		 them in the region's dedicated list.  */
! 	      tree tp_node = r->u.catch.type_list;
! 
! 	      for (;tp_node; tp_node = TREE_CHAIN (tp_node))
! 		{
! 		  int flt = add_ttypes_entry (ttypes, TREE_VALUE (tp_node));
! 		  tree flt_node = build_int_2 (flt, 0);
! 		  
! 		  r->u.catch.filter_list 
! 		    = tree_cons (NULL_TREE, flt_node, r->u.catch.filter_list);
! 		}
! 	    }
! 	  else
! 	    {
! 	      /* Get a filter value for the NULL list also since it will need
! 		 an action record anyway.  */
! 	      int flt = add_ttypes_entry (ttypes, NULL);
! 	      tree flt_node = build_int_2 (flt, 0);
! 	      
! 	      r->u.catch.filter_list 
! 		= tree_cons (NULL_TREE, flt_node, r->u.catch.filter_list);
! 	    }
! 	      
  	  break;
  
  	case ERT_ALLOWED_EXCEPTIONS:
*************** build_post_landing_pads ()
*** 1747,1759 ****
  	    for (c = region->u.try.catch; c ; c = c->u.catch.next_catch)
  	      {
  		/* ??? _Unwind_ForcedUnwind wants no match here.  */
! 		if (c->u.catch.type == NULL)
  		  emit_jump (c->label);
  		else
! 		  emit_cmp_and_jump_insns (cfun->eh->filter,
! 					   GEN_INT (c->u.catch.filter),
! 					   EQ, NULL_RTX, word_mode,
! 					   0, 0, c->label);
  	      }
  	  }
  
--- 1795,1822 ----
  	    for (c = region->u.try.catch; c ; c = c->u.catch.next_catch)
  	      {
  		/* ??? _Unwind_ForcedUnwind wants no match here.  */
! 		if (c->u.catch.type_list == NULL)
  		  emit_jump (c->label);
  		else
! 		  {
! 		    /* Need for one cmp/jump per type caught. Each type
! 		       list entry has a matching entry in the filter list
! 		       (see assign_filter_values).  */
! 		    tree tp_node = c->u.catch.type_list;
! 		    tree flt_node = c->u.catch.filter_list;
! 
! 		    for (;tp_node;)
! 		      {
! 			emit_cmp_and_jump_insns
! 			  (cfun->eh->filter,
! 			   GEN_INT (TREE_INT_CST_LOW (TREE_VALUE (flt_node))),
! 			   EQ, NULL_RTX, word_mode,
! 			   0, 0, c->label);
! 
! 			tp_node = TREE_CHAIN (tp_node);
! 			flt_node = TREE_CHAIN (flt_node);
! 		      }
! 		  }
  	      }
  	  }
  
*************** reachable_next_level (region, type_throw
*** 2571,2577 ****
  	    /* A catch-all handler ends the search.  */
  	    /* ??? _Unwind_ForcedUnwind will want outer cleanups
  	       to be run as well.  */
! 	    if (c->u.catch.type == NULL)
  	      {
  		add_reachable_handler (info, region, c);
  		return RNL_CAUGHT;
--- 2634,2640 ----
  	    /* A catch-all handler ends the search.  */
  	    /* ??? _Unwind_ForcedUnwind will want outer cleanups
  	       to be run as well.  */
! 	    if (c->u.catch.type_list == NULL)
  	      {
  		add_reachable_handler (info, region, c);
  		return RNL_CAUGHT;
*************** reachable_next_level (region, type_throw
*** 2579,2592 ****
  
  	    if (type_thrown)
  	      {
! 		/* If we have a type match, end the search.  */
! 		if (c->u.catch.type == type_thrown
! 		    || (lang_eh_type_covers
! 			&& (*lang_eh_type_covers) (c->u.catch.type,
! 						   type_thrown)))
  		  {
! 		    add_reachable_handler (info, region, c);
! 		    return RNL_CAUGHT;
  		  }
  
  		/* If we have definitive information of a match failure,
--- 2642,2661 ----
  
  	    if (type_thrown)
  	      {
! 		/* If we have a at least one type match, end the search.  */
! 		tree tp_node = c->u.catch.type_list;
! 		
! 		for (; tp_node; tp_node = TREE_CHAIN (tp_node))
  		  {
! 		    tree type = TREE_VALUE (tp_node);
! 
! 		    if (type == type_thrown
! 			|| (lang_eh_type_covers
! 			    && (*lang_eh_type_covers) (type, type_thrown)))
! 		      {
! 			add_reachable_handler (info, region, c);
! 			return RNL_CAUGHT;
! 		      }
  		  }
  
  		/* If we have definitive information of a match failure,
*************** reachable_next_level (region, type_throw
*** 2595,2613 ****
  		  return RNL_NOT_CAUGHT;
  	      }
  
  	    if (! info)
  	      ret = RNL_MAYBE_CAUGHT;
! 
! 	    /* A type must not have been previously caught.  */
! 	    else if (! check_handled (info->types_caught, c->u.catch.type))
  	      {
! 		add_reachable_handler (info, region, c);
! 		info->types_caught = tree_cons (NULL, c->u.catch.type,
! 						info->types_caught);
  
! 		/* ??? If the catch type is a base class of every allowed
! 		   type, then we know we can stop the search.  */
! 		ret = RNL_MAYBE_CAUGHT;
  	      }
  	  }
  
--- 2664,2712 ----
  		  return RNL_NOT_CAUGHT;
  	      }
  
+ 	    /* At this point, we either don't know what type is thrown or
+ 	       don't have front-end assistance to help deciding if it is
+ 	       covered by one of the types in the list for this region.
+ 	    
+ 	       We'd then like to add this region to the list of reachable
+ 	       handlers since it is indeed potentially reachable based on the
+ 	       information we have. 
+ 	       
+ 	       Actually, this handler is for sure not reachable if all the
+ 	       types it matches have already been caught. That is, it is only
+ 	       potentially reachable if at least one of the types it catches
+ 	       has not been previously caught.  */
+ 
  	    if (! info)
  	      ret = RNL_MAYBE_CAUGHT;
! 	    else
  	      {
! 		tree tp_node = c->u.catch.type_list;
! 		bool maybe_reachable = false;
  
! 		/* Compute the potential reachability of this handler and
! 		   update the list of types caught at the same time.  */
! 		for (; tp_node; tp_node = TREE_CHAIN (tp_node))
! 		  {
! 		    tree type = TREE_VALUE (tp_node);
! 
! 		    if (! check_handled (info->types_caught, type))
! 		      {
! 			info->types_caught
! 			  = tree_cons (NULL, type, info->types_caught);
! 			
! 			maybe_reachable = true;
! 		      }
! 		  }
! 		
! 		if (maybe_reachable)
! 		  {
! 		    add_reachable_handler (info, region, c);
! 		
! 		    /* ??? If the catch type is a base class of every allowed
! 		       type, then we know we can stop the search.  */
! 		    ret = RNL_MAYBE_CAUGHT;
! 		  }
  	      }
  	  }
  
*************** collect_one_action_chain (ar_hash, regio
*** 3147,3156 ****
        next = -3;
        for (c = region->u.try.last_catch; c ; c = c->u.catch.prev_catch)
  	{
! 	  if (c->u.catch.type == NULL)
! 	    next = add_action_record (ar_hash, c->u.catch.filter, 0);
  	  else
  	    {
  	      if (next == -3)
  		{
  		  next = collect_one_action_chain (ar_hash, region->outer);
--- 3246,3266 ----
        next = -3;
        for (c = region->u.try.last_catch; c ; c = c->u.catch.prev_catch)
  	{
! 	  if (c->u.catch.type_list == NULL)
! 	    {
! 	      /* Retrieve the filter from the head of the filter list
! 		 where we have stored it (see assign_filter_values).  */
! 	      int filter 
! 		= TREE_INT_CST_LOW (TREE_VALUE (c->u.catch.filter_list));
! 
! 	      next = add_action_record (ar_hash, filter, 0);
! 	    }
  	  else
  	    {
+ 	      /* Once the outer search is done, trigger an action record for
+                  each filter we have.  */
+ 	      tree flt_node;
+ 
  	      if (next == -3)
  		{
  		  next = collect_one_action_chain (ar_hash, region->outer);
*************** collect_one_action_chain (ar_hash, regio
*** 3165,3171 ****
  		  else if (next <= 0)
  		    next = add_action_record (ar_hash, 0, 0);
  		}
! 	      next = add_action_record (ar_hash, c->u.catch.filter, next);
  	    }
  	}
        return next;
--- 3275,3287 ----
  		  else if (next <= 0)
  		    next = add_action_record (ar_hash, 0, 0);
  		}
! 	      
! 	      flt_node = c->u.catch.filter_list;
! 	      for (; flt_node; flt_node = TREE_CHAIN (flt_node))
! 		{
! 		  int filter = TREE_INT_CST_LOW (TREE_VALUE (flt_node));
! 		  next = add_action_record (ar_hash, filter, next);
! 		}
  	    }
  	}
        return next;
*** except.h.ori	Thu Nov 15 10:05:56 2001
--- except.h	Wed Nov 14 10:29:57 2001
*************** extern void expand_eh_region_end_cleanup
*** 61,67 ****
  extern void expand_start_all_catch		PARAMS ((void));
  
  /* Begin a catch clause.  TYPE is an object to be matched by the
!    runtime, or null if this is a catch-all clause.  */
  extern void expand_start_catch			PARAMS ((tree));
  
  /* End a catch clause.  Control will resume after the try/catch block.  */
--- 61,68 ----
  extern void expand_start_all_catch		PARAMS ((void));
  
  /* Begin a catch clause.  TYPE is an object to be matched by the
!    runtime, or a list of such objects, or null if this is a catch-all
!    clause.  */
  extern void expand_start_catch			PARAMS ((tree));
  
  /* End a catch clause.  Control will resume after the try/catch block.  */


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]