except.c: Support for catching a list of types with a single handler (struct eh_region):...

* 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.

From-SVN: r47087
This commit is contained in:
Olivier Hainque 2001-11-16 13:48:18 +01:00 committed by Richard Kenner
parent a8ca89dca8
commit 6d41a92f7c
3 changed files with 178 additions and 40 deletions

View File

@ -1,3 +1,25 @@
2001-11-16 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.
Fri Nov 16 07:12:51 2001 Richard Kenner <kenner@vlsi1.ultra.nyu.edu>
* expr.c (expand_expr, case ADDR_EXPR): Only copy for misaligned if

View File

@ -148,13 +148,13 @@ struct eh_region
rtx continue_label;
} try;
/* The list through the catch handlers, the type object
matched, and a pointer to the generated code. */
/* 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;
int filter;
tree type_list;
tree filter_list;
} catch;
/* A tree_list of allowed types. */
@ -485,7 +485,8 @@ mark_eh_region (region)
ggc_mark_rtx (region->u.try.continue_label);
break;
case ERT_CATCH:
ggc_mark_tree (region->u.catch.type);
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);
@ -767,26 +768,44 @@ expand_start_all_catch ()
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. */
/* 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)
tree type;
expand_start_catch (type_or_list)
tree type_or_list;
{
struct eh_region *t, *c, *l;
tree type_list;
if (! doing_eh (0))
return;
if (type)
add_type_for_runtime (type);
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 = type;
c->u.catch.type_list = type_list;
c->label = gen_label_rtx ();
l = t->u.try.last_catch;
@ -1348,7 +1367,7 @@ duplicate_eh_region_1 (o, map)
break;
case ERT_CATCH:
n->u.catch.type = o->u.catch.type;
n->u.catch.type_list = o->u.catch.type_list;
break;
case ERT_ALLOWED_EXCEPTIONS:
@ -1693,7 +1712,36 @@ assign_filter_values ()
switch (r->type)
{
case ERT_CATCH:
r->u.catch.filter = add_ttypes_entry (ttypes, r->u.catch.type);
/* 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:
@ -1747,13 +1795,27 @@ build_post_landing_pads ()
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)
if (c->u.catch.type_list == 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,
c->label);
{
/* 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_low_cst (TREE_VALUE (flt_node), 0)),
EQ, NULL_RTX, word_mode, 0, c->label);
tp_node = TREE_CHAIN (tp_node);
flt_node = TREE_CHAIN (flt_node);
}
}
}
}
@ -2568,7 +2630,7 @@ reachable_next_level (region, type_thrown, info)
/* A catch-all handler ends the search. */
/* ??? _Unwind_ForcedUnwind will want outer cleanups
to be run as well. */
if (c->u.catch.type == NULL)
if (c->u.catch.type_list == NULL)
{
add_reachable_handler (info, region, c);
return RNL_CAUGHT;
@ -2576,14 +2638,20 @@ reachable_next_level (region, type_thrown, info)
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)))
/* 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))
{
add_reachable_handler (info, region, c);
return RNL_CAUGHT;
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,
@ -2592,19 +2660,49 @@ reachable_next_level (region, type_thrown, info)
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;
/* A type must not have been previously caught. */
else if (! check_handled (info->types_caught, c->u.catch.type))
else
{
add_reachable_handler (info, region, c);
info->types_caught = tree_cons (NULL, c->u.catch.type,
info->types_caught);
tree tp_node = c->u.catch.type_list;
bool maybe_reachable = false;
/* ??? If the catch type is a base class of every allowed
type, then we know we can stop the search. */
ret = RNL_MAYBE_CAUGHT;
/* 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;
}
}
}
@ -3144,10 +3242,21 @@ collect_one_action_chain (ar_hash, region)
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);
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);
@ -3162,7 +3271,13 @@ collect_one_action_chain (ar_hash, region)
else if (next <= 0)
next = add_action_record (ar_hash, 0, 0);
}
next = add_action_record (ar_hash, c->u.catch.filter, next);
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;

View File

@ -61,7 +61,8 @@ extern void expand_eh_region_end_cleanup PARAMS ((tree));
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. */
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. */