- if (o->aka)
- {
- i = bitmap_first_set_bit (o->aka);
- if (i < *min)
- *min = i;
- i = bitmap_last_set_bit (o->aka);
- if (i > *max)
- *max = i;
- }
- if (o->region_number < *min)
- *min = o->region_number;
- if (o->region_number > *max)
- *max = o->region_number;
-
- if (o->inner)
- {
- o = o->inner;
- duplicate_eh_regions_0 (o, min, max);
- while (o->next_peer)
- {
- o = o->next_peer;
- duplicate_eh_regions_0 (o, min, max);
- }
- }
-}
-
-/* A subroutine of duplicate_eh_regions. Copy the region tree under OLD.
- Root it at OUTER, and apply EH_OFFSET to the region number. Don't worry
- about the other internal pointers just yet, just the tree-like pointers. */
-
-static eh_region
-duplicate_eh_regions_1 (eh_region old, eh_region outer, int eh_offset)
-{
- eh_region ret, n;
-
- ret = n = GGC_NEW (struct eh_region);
-
- *n = *old;
- n->outer = outer;
- n->next_peer = NULL;
- if (old->aka)
- {
- unsigned i;
- bitmap_iterator bi;
- n->aka = BITMAP_GGC_ALLOC ();
-
- EXECUTE_IF_SET_IN_BITMAP (old->aka, 0, i, bi)
- {
- bitmap_set_bit (n->aka, i + eh_offset);
- VEC_replace (eh_region, cfun->eh->region_array, i + eh_offset, n);
- }
- }
-
- n->region_number += eh_offset;
- VEC_replace (eh_region, cfun->eh->region_array, n->region_number, n);
-
- if (old->inner)
- {
- old = old->inner;
- n = n->inner = duplicate_eh_regions_1 (old, ret, eh_offset);
- while (old->next_peer)
- {
- old = old->next_peer;
- n = n->next_peer = duplicate_eh_regions_1 (old, ret, eh_offset);
- }
- }
-
- return ret;
-}
-
-/* Duplicate the EH regions of IFUN, rooted at COPY_REGION, into current
- function and root the tree below OUTER_REGION. Remap labels using MAP
- callback. The special case of COPY_REGION of 0 means all regions. */
-
-int
-duplicate_eh_regions (struct function *ifun, duplicate_eh_regions_map map,
- void *data, int copy_region, int outer_region)
-{
- eh_region cur, prev_try, outer, *splice;
- int i, min_region, max_region, eh_offset, cfun_last_region_number;
- int num_regions;
-
- if (!ifun->eh)
- return 0;
-#ifdef ENABLE_CHECKING
- verify_eh_tree (ifun);
-#endif
-
- /* Find the range of region numbers to be copied. The interface we
- provide here mandates a single offset to find new number from old,
- which means we must look at the numbers present, instead of the
- count or something else. */
- if (copy_region > 0)
- {
- min_region = INT_MAX;
- max_region = 0;
-
- cur = VEC_index (eh_region, ifun->eh->region_array, copy_region);
- duplicate_eh_regions_0 (cur, &min_region, &max_region);
- }
- else
- min_region = 1, max_region = ifun->eh->last_region_number;
- num_regions = max_region - min_region + 1;
- cfun_last_region_number = cfun->eh->last_region_number;
- eh_offset = cfun_last_region_number + 1 - min_region;
-
- /* If we've not yet created a region array, do so now. */
- cfun->eh->last_region_number = cfun_last_region_number + num_regions;
- VEC_safe_grow_cleared (eh_region, gc, cfun->eh->region_array,
- cfun->eh->last_region_number + 1);
-
- /* Locate the spot at which to insert the new tree. */
- if (outer_region > 0)
- {
- outer = VEC_index (eh_region, cfun->eh->region_array, outer_region);
- if (outer)
- splice = &outer->inner;
- else
- splice = &cfun->eh->region_tree;
- }
- else
- {
- outer = NULL;
- splice = &cfun->eh->region_tree;
- }
- while (*splice)
- splice = &(*splice)->next_peer;
-
- if (!ifun->eh->region_tree)
- {
- if (outer)
- for (i = cfun_last_region_number + 1;
- i <= cfun->eh->last_region_number; i++)
- {
- VEC_replace (eh_region, cfun->eh->region_array, i, outer);
- if (outer->aka == NULL)
- outer->aka = BITMAP_GGC_ALLOC ();
- bitmap_set_bit (outer->aka, i);
- }
- return eh_offset;
- }
-
- /* Copy all the regions in the subtree. */
- if (copy_region > 0)
- {
- cur = VEC_index (eh_region, ifun->eh->region_array, copy_region);
- *splice = duplicate_eh_regions_1 (cur, outer, eh_offset);
- }
- else
- {
- eh_region n;
-
- cur = ifun->eh->region_tree;
- *splice = n = duplicate_eh_regions_1 (cur, outer, eh_offset);
- while (cur->next_peer)
- {
- cur = cur->next_peer;
- n = n->next_peer = duplicate_eh_regions_1 (cur, outer, eh_offset);
- }
- }
-
- /* Remap all the labels in the new regions. */
- for (i = cfun_last_region_number + 1;
- VEC_iterate (eh_region, cfun->eh->region_array, i, cur); ++i)
- if (cur && cur->tree_label)
- cur->tree_label = map (cur->tree_label, data);
-
- /* 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 =
- VEC_index (eh_region, cfun->eh->region_array, outer_region);
- prev_try && prev_try->type != ERT_TRY; prev_try = prev_try->outer)
- if (prev_try->type == ERT_MUST_NOT_THROW
- || (prev_try->type == ERT_ALLOWED_EXCEPTIONS
- && !prev_try->u.allowed.type_list))
- {
- prev_try = NULL;
- break;
- }
-
- /* Remap all of the internal catch and cleanup linkages. Since we
- duplicate entire subtrees, all of the referenced regions will have
- been copied too. And since we renumbered them as a block, a simple
- bit of arithmetic finds us the index for the replacement region. */
- for (i = cfun_last_region_number + 1;
- VEC_iterate (eh_region, cfun->eh->region_array, i, cur); ++i)
- {
- /* All removed EH that is toplevel in input function is now
- in outer EH of output function. */
- if (cur == NULL)
- {
- gcc_assert (VEC_index
- (eh_region, ifun->eh->region_array,
- i - eh_offset) == NULL);
- if (outer)
- {
- VEC_replace (eh_region, cfun->eh->region_array, i, outer);
- if (outer->aka == NULL)
- outer->aka = BITMAP_GGC_ALLOC ();
- bitmap_set_bit (outer->aka, i);
- }
- continue;
- }
- if (i != cur->region_number)
- continue;
-
-#define REMAP(REG) \
- (REG) = VEC_index (eh_region, cfun->eh->region_array, \
- (REG)->region_number + eh_offset)
-
- switch (cur->type)
- {
- case ERT_TRY:
- if (cur->u.eh_try.eh_catch)
- REMAP (cur->u.eh_try.eh_catch);
- if (cur->u.eh_try.last_catch)
- REMAP (cur->u.eh_try.last_catch);
- break;
-
- case ERT_CATCH:
- if (cur->u.eh_catch.next_catch)
- REMAP (cur->u.eh_catch.next_catch);
- if (cur->u.eh_catch.prev_catch)
- REMAP (cur->u.eh_catch.prev_catch);
- break;
-
- case ERT_CLEANUP:
- if (cur->u.cleanup.prev_try)
- REMAP (cur->u.cleanup.prev_try);
- else
- cur->u.cleanup.prev_try = prev_try;
- break;
-
- default:
- break;
- }
-
-#undef REMAP
- }
-#ifdef ENABLE_CHECKING
- verify_eh_tree (cfun);
-#endif
-
- return eh_offset;
-}
-
-/* Return true if REGION_A is outer to REGION_B in IFUN. */
-
-bool
-eh_region_outer_p (struct function *ifun, int region_a, int region_b)
-{
- struct eh_region *rp_a, *rp_b;
-
- gcc_assert (ifun->eh->last_region_number > 0);
- gcc_assert (ifun->eh->region_tree);
-
- rp_a = VEC_index (eh_region, ifun->eh->region_array, region_a);
- rp_b = VEC_index (eh_region, ifun->eh->region_array, region_b);
- gcc_assert (rp_a != NULL);
- gcc_assert (rp_b != NULL);
-
- do
- {
- if (rp_a == rp_b)
- return true;
- rp_b = rp_b->outer;
- }
- while (rp_b);
-
- return false;
-}
-
-/* Return region number of region that is outer to both if REGION_A and
- REGION_B in IFUN. */
-
-int
-eh_region_outermost (struct function *ifun, int region_a, int region_b)
-{
- struct eh_region *rp_a, *rp_b;
- sbitmap b_outer;
-
- gcc_assert (ifun->eh->last_region_number > 0);
- gcc_assert (ifun->eh->region_tree);
-
- rp_a = VEC_index (eh_region, ifun->eh->region_array, region_a);
- rp_b = VEC_index (eh_region, ifun->eh->region_array, region_b);
- gcc_assert (rp_a != NULL);
- gcc_assert (rp_b != NULL);
-
- b_outer = sbitmap_alloc (ifun->eh->last_region_number + 1);
- sbitmap_zero (b_outer);
-
- do
- {
- SET_BIT (b_outer, rp_b->region_number);
- rp_b = rp_b->outer;
- }
- while (rp_b);
-
- do
- {
- if (TEST_BIT (b_outer, rp_a->region_number))
- {
- sbitmap_free (b_outer);
- return rp_a->region_number;
- }
- rp_a = rp_a->outer;
- }
- while (rp_a);
-
- sbitmap_free (b_outer);
- return -1;
-}
-\f
-static int
-t2r_eq (const void *pentry, const void *pdata)
-{
- const_tree const entry = (const_tree) pentry;
- const_tree const data = (const_tree) pdata;
-
- return TREE_PURPOSE (entry) == data;
-}
-
-static hashval_t
-t2r_hash (const void *pentry)
-{
- const_tree const entry = (const_tree) pentry;
- return TREE_HASH (TREE_PURPOSE (entry));
-}
-
-static void
-add_type_for_runtime (tree type)
-{
- tree *slot;
-
- slot = (tree *) htab_find_slot_with_hash (type_to_runtime_map, type,
- TREE_HASH (type), INSERT);
- if (*slot == NULL)
- {
- tree runtime = (*lang_eh_runtime_type) (type);
- *slot = tree_cons (type, runtime, NULL_TREE);
- }
-}
-
-static tree
-lookup_type_for_runtime (tree type)
-{
- tree *slot;
-
- slot = (tree *) htab_find_slot_with_hash (type_to_runtime_map, type,
- TREE_HASH (type), NO_INSERT);
-
- /* We should have always inserted the data earlier. */
- return TREE_VALUE (*slot);
-}
-
-\f
-/* Represent an entry in @TTypes for either catch actions
- or exception filter actions. */
-struct ttypes_filter GTY(())
-{
- tree t;
- int filter;
-};
-
-/* Compare ENTRY (a ttypes_filter entry in the hash table) with DATA
- (a tree) for a @TTypes type node we are thinking about adding. */
-
-static int
-ttypes_filter_eq (const void *pentry, const void *pdata)
-{
- const struct ttypes_filter *const entry
- = (const struct ttypes_filter *) pentry;
- const_tree const data = (const_tree) pdata;
-
- return entry->t == data;
-}