This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Add support for a TREE_LIST of types to expand_start_catch
- From: Olivier Hainque <hainque at ACT-Europe dot FR>
- To: gcc-patches at gcc dot gnu dot org
- Cc: rth at redhat dot com
- Date: 15 Nov 2001 15:59:27 +0100
- Subject: 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. */