/* Implements exception handling.
Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
Contributed by Mike Stump <mrs@cygnus.com>.
This file is part of GCC.
#include "target.h"
#include "langhooks.h"
#include "cgraph.h"
+#include "diagnostic.h"
/* Provide defaults for stuff that may not be defined when using
sjlj exceptions. */
ERT_CATCH,
ERT_ALLOWED_EXCEPTIONS,
ERT_MUST_NOT_THROW,
- ERT_THROW,
- ERT_FIXUP
+ ERT_THROW
} type;
/* Holds the action to perform based on the preceding type. */
struct eh_region_u_try {
struct eh_region *catch;
struct eh_region *last_catch;
- struct eh_region *prev_try;
- rtx continue_label;
} GTY ((tag ("ERT_TRY"))) try;
/* The list through the catch handlers, the list of type objects
/* Retain the cleanup expression even after expansion so that
we can match up fixup regions. */
struct eh_region_u_cleanup {
- tree exp;
struct eh_region *prev_try;
} GTY ((tag ("ERT_CLEANUP"))) cleanup;
-
- /* The real region (by expression and by pointer) that fixup code
- should live in. */
- struct eh_region_u_fixup {
- tree cleanup_exp;
- struct eh_region *real_region;
- bool resolved;
- } GTY ((tag ("ERT_FIXUP"))) fixup;
} GTY ((desc ("%0.type"))) u;
/* Entry point for this region's handler before landing pads are built. */
int built_landing_pads;
int last_region_number;
- varray_type ttype_data;
+ VEC(tree,gc) *ttype_data;
varray_type ehspec_data;
varray_type action_record_data;
rtx sjlj_fc;
rtx sjlj_exit_after;
+
+ htab_t GTY((param_is (struct throw_stmt_node))) throw_stmt_table;
};
\f
static void add_type_for_runtime (tree);
static tree lookup_type_for_runtime (tree);
-static void resolve_fixup_regions (void);
-static void remove_fixup_regions (void);
static void remove_unreachable_regions (rtx);
-static void convert_from_eh_region_ranges_1 (rtx *, int *, int);
-static struct eh_region *duplicate_eh_region_1 (struct eh_region *,
- struct inline_remap *);
-static void duplicate_eh_region_2 (struct eh_region *, struct eh_region **);
static int ttypes_filter_eq (const void *, const void *);
static hashval_t ttypes_filter_hash (const void *);
static int ehspec_filter_eq (const void *, const void *);
}
}
-static void
-resolve_one_fixup_region (struct eh_region *fixup)
-{
- struct eh_region *cleanup, *real;
- int j, n;
-
- n = cfun->eh->last_region_number;
- cleanup = 0;
-
- for (j = 1; j <= n; ++j)
- {
- cleanup = cfun->eh->region_array[j];
- if (cleanup && cleanup->type == ERT_CLEANUP
- && cleanup->u.cleanup.exp == fixup->u.fixup.cleanup_exp)
- break;
- }
- gcc_assert (j <= n);
-
- real = cleanup->outer;
- if (real && real->type == ERT_FIXUP)
- {
- if (!real->u.fixup.resolved)
- resolve_one_fixup_region (real);
- real = real->u.fixup.real_region;
- }
-
- fixup->u.fixup.real_region = real;
- fixup->u.fixup.resolved = true;
-}
-
-static void
-resolve_fixup_regions (void)
-{
- int i, n = cfun->eh->last_region_number;
-
- for (i = 1; i <= n; ++i)
- {
- struct eh_region *fixup = cfun->eh->region_array[i];
-
- if (!fixup || fixup->type != ERT_FIXUP || fixup->u.fixup.resolved)
- continue;
-
- resolve_one_fixup_region (fixup);
- }
-}
-
-/* Now that we've discovered what region actually encloses a fixup,
- we can shuffle pointers and remove them from the tree. */
-
-static void
-remove_fixup_regions (void)
-{
- int i;
- rtx insn, note;
- struct eh_region *fixup;
-
- /* Walk the insn chain and adjust the REG_EH_REGION numbers
- for instructions referencing fixup regions. This is only
- strictly necessary for fixup regions with no parent, but
- doesn't hurt to do it for all regions. */
- for (insn = get_insns(); insn ; insn = NEXT_INSN (insn))
- if (INSN_P (insn)
- && (note = find_reg_note (insn, REG_EH_REGION, NULL))
- && INTVAL (XEXP (note, 0)) > 0
- && (fixup = cfun->eh->region_array[INTVAL (XEXP (note, 0))])
- && fixup->type == ERT_FIXUP)
- {
- if (fixup->u.fixup.real_region)
- XEXP (note, 0) = GEN_INT (fixup->u.fixup.real_region->region_number);
- else
- remove_note (insn, note);
- }
-
- /* Remove the fixup regions from the tree. */
- for (i = cfun->eh->last_region_number; i > 0; --i)
- {
- fixup = cfun->eh->region_array[i];
- if (! fixup)
- continue;
-
- /* Allow GC to maybe free some memory. */
- if (fixup->type == ERT_CLEANUP)
- fixup->u.cleanup.exp = NULL_TREE;
-
- if (fixup->type != ERT_FIXUP)
- continue;
-
- if (fixup->inner)
- {
- struct eh_region *parent, *p, **pp;
-
- parent = fixup->u.fixup.real_region;
-
- /* Fix up the children's parent pointers; find the end of
- the list. */
- for (p = fixup->inner; ; p = p->next_peer)
- {
- p->outer = parent;
- if (! p->next_peer)
- break;
- }
-
- /* In the tree of cleanups, only outer-inner ordering matters.
- So link the children back in anywhere at the correct level. */
- if (parent)
- pp = &parent->inner;
- else
- pp = &cfun->eh->region_tree;
- p->next_peer = *pp;
- *pp = fixup->inner;
- fixup->inner = NULL;
- }
-
- remove_eh_handler (fixup);
- }
-}
-
/* Remove all regions whose labels are not reachable from insns. */
static void
free (uid_region_num);
}
-/* Turn NOTE_INSN_EH_REGION notes into REG_EH_REGION notes for each
- can_throw instruction in the region. */
-
-static void
-convert_from_eh_region_ranges_1 (rtx *pinsns, int *orig_sp, int cur)
-{
- int *sp = orig_sp;
- rtx insn, next;
-
- for (insn = *pinsns; insn ; insn = next)
- {
- next = NEXT_INSN (insn);
- if (NOTE_P (insn))
- {
- int kind = NOTE_LINE_NUMBER (insn);
- if (kind == NOTE_INSN_EH_REGION_BEG
- || kind == NOTE_INSN_EH_REGION_END)
- {
- if (kind == NOTE_INSN_EH_REGION_BEG)
- {
- struct eh_region *r;
-
- *sp++ = cur;
- cur = NOTE_EH_HANDLER (insn);
-
- r = cfun->eh->region_array[cur];
- if (r->type == ERT_FIXUP)
- {
- r = r->u.fixup.real_region;
- cur = r ? r->region_number : 0;
- }
- else if (r->type == ERT_CATCH)
- {
- r = r->outer;
- cur = r ? r->region_number : 0;
- }
- }
- else
- cur = *--sp;
-
- if (insn == *pinsns)
- *pinsns = next;
- remove_insn (insn);
- continue;
- }
- }
- else if (INSN_P (insn))
- {
- if (cur > 0
- && ! find_reg_note (insn, REG_EH_REGION, NULL_RTX)
- /* Calls can always potentially throw exceptions, unless
- they have a REG_EH_REGION note with a value of 0 or less.
- Which should be the only possible kind so far. */
- && (CALL_P (insn)
- /* If we wanted exceptions for non-call insns, then
- any may_trap_p instruction could throw. */
- || (flag_non_call_exceptions
- && GET_CODE (PATTERN (insn)) != CLOBBER
- && GET_CODE (PATTERN (insn)) != USE
- && may_trap_p (PATTERN (insn)))))
- {
- REG_NOTES (insn) = alloc_EXPR_LIST (REG_EH_REGION, GEN_INT (cur),
- REG_NOTES (insn));
- }
- }
- }
-
- gcc_assert (sp == orig_sp);
-}
-
-static void
-collect_rtl_labels_from_trees (void)
-{
- int i, n = cfun->eh->last_region_number;
- for (i = 1; i <= n; ++i)
- {
- struct eh_region *reg = cfun->eh->region_array[i];
- if (reg && reg->tree_label)
- reg->label = DECL_RTL_IF_SET (reg->tree_label);
- }
-}
+/* Set up EH labels for RTL. */
void
convert_from_eh_region_ranges (void)
{
rtx insns = get_insns ();
+ int i, n = cfun->eh->last_region_number;
- if (cfun->eh->region_array)
- {
- /* If the region array already exists, assume we're coming from
- optimize_function_tree. In this case all we need to do is
- collect the rtl labels that correspond to the tree labels
- that we allocated earlier. */
- collect_rtl_labels_from_trees ();
- }
- else
+ /* Most of the work is already done at the tree level. All we need to
+ do is collect the rtl labels that correspond to the tree labels that
+ collect the rtl labels that correspond to the tree labels
+ we allocated earlier. */
+ for (i = 1; i <= n; ++i)
{
- int *stack;
-
- collect_eh_region_array ();
- resolve_fixup_regions ();
-
- stack = xmalloc (sizeof (int) * (cfun->eh->last_region_number + 1));
- convert_from_eh_region_ranges_1 (&insns, stack, 0);
- free (stack);
-
- remove_fixup_regions ();
+ struct eh_region *region = cfun->eh->region_array[i];
+ if (region && region->tree_label)
+ region->label = DECL_RTL_IF_SET (region->tree_label);
}
remove_unreachable_regions (insns);
}
\f
static struct eh_region *
-duplicate_eh_region_1 (struct eh_region *o, struct inline_remap *map)
+duplicate_eh_region_1 (struct eh_region *o)
{
struct eh_region *n = ggc_alloc_cleared (sizeof (struct eh_region));
+ *n = *o;
+
n->region_number = o->region_number + cfun->eh->last_region_number;
- n->type = o->type;
-
- switch (n->type)
- {
- case ERT_CLEANUP:
- case ERT_MUST_NOT_THROW:
- break;
-
- case ERT_TRY:
- if (o->u.try.continue_label)
- n->u.try.continue_label
- = get_label_from_map (map,
- CODE_LABEL_NUMBER (o->u.try.continue_label));
- break;
-
- case ERT_CATCH:
- n->u.catch.type_list = o->u.catch.type_list;
- break;
-
- case ERT_ALLOWED_EXCEPTIONS:
- n->u.allowed.type_list = o->u.allowed.type_list;
- break;
-
- case ERT_THROW:
- n->u.throw.type = o->u.throw.type;
-
- default:
- gcc_unreachable ();
- }
-
- if (o->label)
- n->label = get_label_from_map (map, CODE_LABEL_NUMBER (o->label));
- if (o->resume)
- {
- n->resume = map->insn_map[INSN_UID (o->resume)];
- gcc_assert (n->resume);
- }
-
+ gcc_assert (!o->aka);
+
return n;
}
static void
-duplicate_eh_region_2 (struct eh_region *o, struct eh_region **n_array)
+duplicate_eh_region_2 (struct eh_region *o, struct eh_region **n_array,
+ struct eh_region *prev_try)
{
struct eh_region *n = n_array[o->region_number];
-
+
switch (n->type)
{
case ERT_TRY:
- n->u.try.catch = n_array[o->u.try.catch->region_number];
- n->u.try.last_catch = n_array[o->u.try.last_catch->region_number];
+ if (o->u.try.catch)
+ n->u.try.catch = n_array[o->u.try.catch->region_number];
+ if (o->u.try.last_catch)
+ n->u.try.last_catch = n_array[o->u.try.last_catch->region_number];
break;
-
+
case ERT_CATCH:
if (o->u.catch.next_catch)
n->u.catch.next_catch = n_array[o->u.catch.next_catch->region_number];
n->u.catch.prev_catch = n_array[o->u.catch.prev_catch->region_number];
break;
+ case ERT_CLEANUP:
+ if (o->u.cleanup.prev_try)
+ n->u.cleanup.prev_try = n_array[o->u.cleanup.prev_try->region_number];
+ else
+ n->u.cleanup.prev_try = prev_try;
+ break;
+
default:
break;
}
-
+
if (o->outer)
n->outer = n_array[o->outer->region_number];
if (o->inner)
n->next_peer = n_array[o->next_peer->region_number];
}
+/* Duplicate the EH regions of IFUN into current function, root the tree in
+ OUTER_REGION and remap labels using MAP callback. */
int
-duplicate_eh_regions (struct function *ifun, struct inline_remap *map)
+duplicate_eh_regions (struct function *ifun, duplicate_eh_regions_map map,
+ void *data, int outer_region)
{
int ifun_last_region_number = ifun->eh->last_region_number;
- struct eh_region **n_array, *root, *cur;
+ struct eh_region **n_array, *root, *cur, *prev_try;
int i;
-
- if (ifun_last_region_number == 0)
+
+ if (ifun_last_region_number == 0 || !ifun->eh->region_tree)
return 0;
-
+
n_array = xcalloc (ifun_last_region_number + 1, sizeof (*n_array));
+
+ /* Search for the containing ERT_TRY region to fix up
+ the prev_try short-cuts for ERT_CLEANUP regions. */
+ prev_try = NULL;
+ if (outer_region > 0)
+ for (prev_try = cfun->eh->region_array[outer_region];
+ prev_try && prev_try->type != ERT_TRY;
+ prev_try = prev_try->outer)
+ ;
for (i = 1; i <= ifun_last_region_number; ++i)
{
cur = ifun->eh->region_array[i];
if (!cur || cur->region_number != i)
continue;
- n_array[i] = duplicate_eh_region_1 (cur, map);
+ n_array[i] = duplicate_eh_region_1 (cur);
+ if (cur->tree_label)
+ {
+ tree newlabel = map (cur->tree_label, data);
+ n_array[i]->tree_label = newlabel;
+ }
+ else
+ n_array[i]->tree_label = NULL;
}
for (i = 1; i <= ifun_last_region_number; ++i)
{
cur = ifun->eh->region_array[i];
if (!cur || cur->region_number != i)
continue;
- duplicate_eh_region_2 (cur, n_array);
+ duplicate_eh_region_2 (cur, n_array, prev_try);
}
-
+
root = n_array[ifun->eh->region_tree->region_number];
- cur = cfun->eh->cur_region;
- if (cur)
+ gcc_assert (root->outer == NULL);
+ if (outer_region > 0)
{
+ struct eh_region *cur = cfun->eh->region_array[outer_region];
struct eh_region *p = cur->inner;
+
if (p)
{
while (p->next_peer)
p->next_peer = root;
}
else
- cur->inner = root;
-
+ cur->inner = root;
for (i = 1; i <= ifun_last_region_number; ++i)
if (n_array[i] && n_array[i]->outer == NULL)
n_array[i]->outer = cur;
p->next_peer = root;
}
else
- cfun->eh->region_tree = root;
+ cfun->eh->region_tree = root;
}
-
+
free (n_array);
-
+
i = cfun->eh->last_region_number;
cfun->eh->last_region_number = i + ifun_last_region_number;
+
+ collect_eh_region_array ();
+
return i;
}
-
\f
static int
t2r_eq (const void *pentry, const void *pdata)
n = xmalloc (sizeof (*n));
n->t = type;
- n->filter = VARRAY_ACTIVE_SIZE (cfun->eh->ttype_data) + 1;
+ n->filter = VEC_length (tree, cfun->eh->ttype_data) + 1;
*slot = n;
- VARRAY_PUSH_TREE (cfun->eh->ttype_data, type);
+ VEC_safe_push (tree, gc, cfun->eh->ttype_data, type);
}
return n->filter;
int i;
htab_t ttypes, ehspec;
- VARRAY_TREE_INIT (cfun->eh->ttype_data, 16, "ttype_data");
+ cfun->eh->ttype_data = VEC_alloc (tree, gc, 16);
VARRAY_UCHAR_INIT (cfun->eh->ehspec_data, 64, "ehspec_data");
ttypes = htab_create (31, ttypes_filter_hash, ttypes_filter_eq, free);
rtx last;
basic_block bb;
edge e;
+ edge_iterator ei;
- /* If there happens to be an fallthru edge (possibly created by cleanup_cfg
+ /* If there happens to be a fallthru edge (possibly created by cleanup_cfg
call), we don't want it to go into newly created landing pad or other EH
construct. */
- for (e = BLOCK_FOR_INSN (insn)->pred; e; e = e->pred_next)
+ for (ei = ei_start (BLOCK_FOR_INSN (insn)->preds); (e = ei_safe_edge (ei)); )
if (e->flags & EDGE_FALLTHRU)
force_nonfallthru (e);
+ else
+ ei_next (&ei);
last = emit_insn_before (seq, insn);
if (BARRIER_P (last))
last = PREV_INSN (last);
emit_jump (outer->post_landing_pad);
src = BLOCK_FOR_INSN (region->resume);
dest = BLOCK_FOR_INSN (outer->post_landing_pad);
- while (src->succ)
- remove_edge (src->succ);
+ while (EDGE_COUNT (src->succs) > 0)
+ remove_edge (EDGE_SUCC (src, 0));
e = make_edge (src, dest, 0);
e->probability = REG_BR_PROB_BASE;
e->count = src->count;
|| NOTE_LINE_NUMBER (fn_begin) == NOTE_INSN_BASIC_BLOCK))
break;
if (NOTE_LINE_NUMBER (fn_begin) == NOTE_INSN_FUNCTION_BEG)
- insert_insn_on_edge (seq, ENTRY_BLOCK_PTR->succ);
+ insert_insn_on_edge (seq, single_succ_edge (ENTRY_BLOCK_PTR));
else
{
- rtx last = BB_END (ENTRY_BLOCK_PTR->succ->dest);
+ rtx last = BB_END (single_succ (ENTRY_BLOCK_PTR));
for (; ; fn_begin = NEXT_INSN (fn_begin))
if ((NOTE_P (fn_begin)
&& NOTE_LINE_NUMBER (fn_begin) == NOTE_INSN_FUNCTION_BEG)
{
rtx seq;
edge e;
+ edge_iterator ei;
start_sequence ();
post-dominates all can_throw_internal instructions. This is
the last possible moment. */
- for (e = EXIT_BLOCK_PTR->pred; e; e = e->pred_next)
+ FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR->preds)
if (e->flags & EDGE_FALLTHRU)
break;
if (e)
is inside the last basic block or after it. In the other case
we need to emit to edge. */
gcc_assert (e->src->next_bb == EXIT_BLOCK_PTR);
- for (insn = NEXT_INSN (BB_END (e->src)); insn; insn = NEXT_INSN (insn))
- if (insn == cfun->eh->sjlj_exit_after)
- break;
- if (insn)
- insert_insn_on_edge (seq, e);
- else
+ for (insn = BB_HEAD (e->src); ; insn = NEXT_INSN (insn))
{
- insn = cfun->eh->sjlj_exit_after;
- if (LABEL_P (insn))
- insn = NEXT_INSN (insn);
- emit_insn_after (seq, insn);
+ if (insn == cfun->eh->sjlj_exit_after)
+ {
+ if (LABEL_P (insn))
+ insn = NEXT_INSN (insn);
+ emit_insn_after (seq, insn);
+ return;
+ }
+ if (insn == BB_END (e->src))
+ break;
}
+ insert_insn_on_edge (seq, e);
}
}
commit_edge_insertions ();
FOR_EACH_BB (bb)
{
- edge e, next;
+ edge e;
+ edge_iterator ei;
bool eh = false;
- for (e = bb->succ; e; e = next)
+ for (ei = ei_start (bb->succs); (e = ei_safe_edge (ei)); )
{
- next = e->succ_next;
if (e->flags & EDGE_EH)
{
remove_edge (e);
eh = true;
}
+ else
+ ei_next (&ei);
}
if (eh)
rtl_make_eh_edge (NULL, bb, BB_END (bb));
cfun->eh->region_array[region->region_number] = outer;
if (region->aka)
{
- int i;
- EXECUTE_IF_SET_IN_BITMAP (region->aka, 0, i,
- { cfun->eh->region_array[i] = outer; });
+ unsigned i;
+ bitmap_iterator bi;
+
+ EXECUTE_IF_SET_IN_BITMAP (region->aka, 0, i, bi)
+ {
+ cfun->eh->region_array[i] = outer;
+ }
}
if (outer)
if (!outer->aka)
outer->aka = BITMAP_GGC_ALLOC ();
if (region->aka)
- bitmap_a_or_b (outer->aka, outer->aka, region->aka);
+ bitmap_ior_into (outer->aka, region->aka);
bitmap_set_bit (outer->aka, region->region_number);
}
/* A subroutine of reachable_next_level. Return true if TYPE, or a
base class of TYPE, is in HANDLED. */
-int
+static int
check_handled (tree handled, tree type)
{
tree t;
/* Here we end our search, since no exceptions may propagate.
If we've touched down at some landing pad previous, then the
explicit function call we generated may be used. Otherwise
- the call is made by the runtime. */
- if (info && info->saw_any_handlers)
+ the call is made by the runtime.
+
+ Before inlining, do not perform this optimization. We may
+ inline a subroutine that contains handlers, and that will
+ change the value of saw_any_handlers. */
+
+ if ((info && info->saw_any_handlers) || !cfun->after_inlining)
{
add_reachable_handler (info, region, region);
return RNL_CAUGHT;
return RNL_BLOCKED;
case ERT_THROW:
- case ERT_FIXUP:
case ERT_UNKNOWN:
/* Shouldn't see these here. */
gcc_unreachable ();
within the function. */
bool
-can_throw_internal_1 (int region_number)
+can_throw_internal_1 (int region_number, bool is_resx)
{
struct eh_region *region;
tree type_thrown;
region = cfun->eh->region_array[region_number];
type_thrown = NULL_TREE;
- if (region->type == ERT_THROW)
+ if (is_resx)
+ region = region->outer;
+ else if (region->type == ERT_THROW)
{
type_thrown = region->u.throw.type;
region = region->outer;
if (JUMP_P (insn)
&& GET_CODE (PATTERN (insn)) == RESX
&& XINT (PATTERN (insn), 0) > 0)
- return can_throw_internal_1 (XINT (PATTERN (insn), 0));
+ return can_throw_internal_1 (XINT (PATTERN (insn), 0), true);
if (NONJUMP_INSN_P (insn)
&& GET_CODE (PATTERN (insn)) == SEQUENCE)
if (!note || INTVAL (XEXP (note, 0)) <= 0)
return false;
- return can_throw_internal_1 (INTVAL (XEXP (note, 0)));
+ return can_throw_internal_1 (INTVAL (XEXP (note, 0)), false);
}
/* Determine if the given INSN can throw an exception that is
visible outside the function. */
bool
-can_throw_external_1 (int region_number)
+can_throw_external_1 (int region_number, bool is_resx)
{
struct eh_region *region;
tree type_thrown;
region = cfun->eh->region_array[region_number];
type_thrown = NULL_TREE;
- if (region->type == ERT_THROW)
+ if (is_resx)
+ region = region->outer;
+ else if (region->type == ERT_THROW)
{
type_thrown = region->u.throw.type;
region = region->outer;
if (! INSN_P (insn))
return false;
+ if (JUMP_P (insn)
+ && GET_CODE (PATTERN (insn)) == RESX
+ && XINT (PATTERN (insn), 0) > 0)
+ return can_throw_external_1 (XINT (PATTERN (insn), 0), true);
+
if (NONJUMP_INSN_P (insn)
&& GET_CODE (PATTERN (insn)) == SEQUENCE)
insn = XVECEXP (PATTERN (insn), 0, 0);
if (INTVAL (XEXP (note, 0)) <= 0)
return false;
- return can_throw_external_1 (INTVAL (XEXP (note, 0)));
+ return can_throw_external_1 (INTVAL (XEXP (note, 0)), false);
}
/* Set TREE_NOTHROW and cfun->all_throwers_are_sibcalls. */
if (TREE_CODE (which) != INTEGER_CST)
{
- error ("argument of `__builtin_eh_return_regno' must be constant");
+ error ("argument of %<__builtin_eh_return_regno%> must be constant");
return constm1_rtx;
}
static void
dw2_output_call_site_table (void)
{
- const char *const function_start_lab
- = IDENTIFIER_POINTER (current_function_func_begin_label);
int n = cfun->eh->call_site_data_used;
int i;
/* ??? Perhaps use attr_length to choose data1 or data2 instead of
data4 if the function is small enough. */
#ifdef HAVE_AS_LEB128
- dw2_asm_output_delta_uleb128 (reg_start_lab, function_start_lab,
+ dw2_asm_output_delta_uleb128 (reg_start_lab,
+ current_function_func_begin_label,
"region %d start", i);
dw2_asm_output_delta_uleb128 (reg_end_lab, reg_start_lab,
"length");
if (cs->landing_pad)
- dw2_asm_output_delta_uleb128 (landing_pad_lab, function_start_lab,
+ dw2_asm_output_delta_uleb128 (landing_pad_lab,
+ current_function_func_begin_label,
"landing pad");
else
dw2_asm_output_data_uleb128 (0, "landing pad");
#else
- dw2_asm_output_delta (4, reg_start_lab, function_start_lab,
+ dw2_asm_output_delta (4, reg_start_lab,
+ current_function_func_begin_label,
"region %d start", i);
dw2_asm_output_delta (4, reg_end_lab, reg_start_lab, "length");
if (cs->landing_pad)
- dw2_asm_output_delta (4, landing_pad_lab, function_start_lab,
+ dw2_asm_output_delta (4, landing_pad_lab,
+ current_function_func_begin_label,
"landing pad");
else
dw2_asm_output_data (4, 0, "landing pad");
if (targetm.have_named_sections)
{
int flags;
-#ifdef HAVE_LD_RO_RW_SECTION_MIXING
- int tt_format = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/0, /*global=*/1);
- flags = (! flag_pic
- || ((tt_format & 0x70) != DW_EH_PE_absptr
- && (tt_format & 0x70) != DW_EH_PE_aligned))
- ? 0 : SECTION_WRITE;
-#else
- flags = SECTION_WRITE;
-#endif
+ if (EH_TABLES_CAN_BE_READ_ONLY)
+ {
+ int tt_format = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/0, /*global=*/1);
+
+ flags = (! flag_pic
+ || ((tt_format & 0x70) != DW_EH_PE_absptr
+ && (tt_format & 0x70) != DW_EH_PE_aligned))
+ ? 0 : SECTION_WRITE;
+ }
+ else
+ flags = SECTION_WRITE;
named_section_flags (".gcc_except_table", flags);
}
else if (flag_pic)
#ifdef TARGET_UNWIND_INFO
/* TODO: Move this into target file. */
+ assemble_external_libcall (eh_personality_libfunc);
fputs ("\t.personality\t", asm_out_file);
output_addr_const (asm_out_file, eh_personality_libfunc);
fputs ("\n\t.handlerdata\n", asm_out_file);
targetm.asm_out.exception_section ();
#endif
- have_tt_data = (VARRAY_ACTIVE_SIZE (cfun->eh->ttype_data) > 0
+ have_tt_data = (VEC_length (tree, cfun->eh->ttype_data) > 0
|| VARRAY_ACTIVE_SIZE (cfun->eh->ehspec_data) > 0);
/* Indicate the format of the @TType entries. */
after_disp = (1 + size_of_uleb128 (call_site_len)
+ call_site_len
+ VARRAY_ACTIVE_SIZE (cfun->eh->action_record_data)
- + (VARRAY_ACTIVE_SIZE (cfun->eh->ttype_data)
+ + (VEC_length (tree, cfun->eh->ttype_data)
* tt_format_size));
disp = after_disp;
if (have_tt_data)
assemble_align (tt_format_size * BITS_PER_UNIT);
- i = VARRAY_ACTIVE_SIZE (cfun->eh->ttype_data);
+ i = VEC_length (tree, cfun->eh->ttype_data);
while (i-- > 0)
{
- tree type = VARRAY_TREE (cfun->eh->ttype_data, i);
+ tree type = VEC_index (tree, cfun->eh->ttype_data, i);
rtx value;
if (type == NULL_TREE)
dw2_asm_output_data (1, VARRAY_UCHAR (cfun->eh->ehspec_data, i),
(i ? NULL : "Exception specification table"));
- function_section (current_function_decl);
+ current_function_section (current_function_decl);
+}
+
+void
+set_eh_throw_stmt_table (struct function *fun, struct htab *table)
+{
+ fun->eh->throw_stmt_table = table;
+}
+
+htab_t
+get_eh_throw_stmt_table (struct function *fun)
+{
+ return fun->eh->throw_stmt_table;
+}
+
+/* Dump EH information to OUT. */
+void
+dump_eh_tree (FILE *out, struct function *fun)
+{
+ struct eh_region *i;
+ int depth = 0;
+ static const char * const type_name[] = {"unknown", "cleanup", "try", "catch",
+ "allowed_exceptions", "must_not_throw",
+ "throw"};
+
+ i = fun->eh->region_tree;
+ if (! i)
+ return;
+
+ fprintf (out, "Eh tree:\n");
+ while (1)
+ {
+ fprintf (out, " %*s %i %s", depth * 2, "",
+ i->region_number, type_name [(int)i->type]);
+ if (i->tree_label)
+ {
+ fprintf (out, " tree_label:");
+ print_generic_expr (out, i->tree_label, 0);
+ }
+ fprintf (out, "\n");
+ /* If there are sub-regions, process them. */
+ if (i->inner)
+ i = i->inner, depth++;
+ /* If there are peers, process them. */
+ else if (i->next_peer)
+ i = i->next_peer;
+ /* Otherwise, step back up the tree to the next peer. */
+ else
+ {
+ do {
+ i = i->outer;
+ depth--;
+ if (i == NULL)
+ return;
+ } while (i->next_peer == NULL);
+ i = i->next_peer;
+ }
+ }
}
+/* Verify some basic invariants on EH datastructures. Could be extended to
+ catch more. */
+void
+verify_eh_tree (struct function *fun)
+{
+ struct eh_region *i, *outer = NULL;
+ bool err = false;
+ int nvisited = 0;
+ int count = 0;
+ int j;
+ int depth = 0;
+
+ i = fun->eh->region_tree;
+ if (! i)
+ return;
+ for (j = fun->eh->last_region_number; j > 0; --j)
+ if (fun->eh->region_array[j])
+ {
+ count++;
+ if (fun->eh->region_array[j]->region_number != j)
+ {
+ error ("region_array is corrupted for region %i", i->region_number);
+ err = true;
+ }
+ }
+
+ while (1)
+ {
+ if (fun->eh->region_array[i->region_number] != i)
+ {
+ error ("region_array is corrupted for region %i", i->region_number);
+ err = true;
+ }
+ if (i->outer != outer)
+ {
+ error ("outer block of region %i is wrong", i->region_number);
+ err = true;
+ }
+ if (i->may_contain_throw && outer && !outer->may_contain_throw)
+ {
+ error ("region %i may contain throw and is contained in region that may not",
+ i->region_number);
+ err = true;
+ }
+ if (depth < 0)
+ {
+ error ("negative nesting depth of region %i", i->region_number);
+ err = true;
+ }
+ nvisited ++;
+ /* If there are sub-regions, process them. */
+ if (i->inner)
+ outer = i, i = i->inner, depth++;
+ /* If there are peers, process them. */
+ else if (i->next_peer)
+ i = i->next_peer;
+ /* Otherwise, step back up the tree to the next peer. */
+ else
+ {
+ do {
+ i = i->outer;
+ depth--;
+ if (i == NULL)
+ {
+ if (depth != -1)
+ {
+ error ("Tree list ends on depth %i", depth + 1);
+ err = true;
+ }
+ if (count != nvisited)
+ {
+ error ("array does not match the region tree");
+ err = true;
+ }
+ if (err)
+ {
+ dump_eh_tree (stderr, fun);
+ internal_error ("verify_eh_tree failed.");
+ }
+ return;
+ }
+ outer = i->outer;
+ } while (i->next_peer == NULL);
+ i = i->next_peer;
+ }
+ }
+}
#include "gt-except.h"