+
+#undef REMAP
+ }
+#ifdef ENABLE_CHECKING
+ verify_eh_tree (cfun);
+#endif
+
+ return eh_offset;
+}
+
+/* Return new copy of eh region OLD inside region NEW_OUTER.
+ Do not care about updating the tree otherwise. */
+
+static struct eh_region_d *
+copy_eh_region_1 (struct eh_region_d *old, struct eh_region_d *new_outer)
+{
+ struct eh_region_d *new_eh = gen_eh_region (old->type, new_outer);
+ new_eh->u = old->u;
+ new_eh->tree_label = old->tree_label;
+ new_eh->may_contain_throw = old->may_contain_throw;
+ VEC_safe_grow (eh_region, gc, cfun->eh->region_array,
+ cfun->eh->last_region_number + 1);
+ VEC_replace (eh_region, cfun->eh->region_array, new_eh->region_number, new_eh);
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file, "Copying region %i to %i\n", old->region_number, new_eh->region_number);
+ return new_eh;
+}
+
+/* Return new copy of eh region OLD inside region NEW_OUTER.
+
+ Copy whole catch-try chain if neccesary. */
+
+static struct eh_region_d *
+copy_eh_region (struct eh_region_d *old, struct eh_region_d *new_outer)
+{
+ struct eh_region_d *r, *n, *old_try, *new_try, *ret = NULL;
+ VEC(eh_region,heap) *catch_list = NULL;
+
+ if (old->type != ERT_CATCH)
+ {
+ gcc_assert (old->type != ERT_TRY);
+ r = copy_eh_region_1 (old, new_outer);
+ return r;
+ }
+
+ /* Locate and copy corresponding TRY. */
+ for (old_try = old->next_peer; old_try->type == ERT_CATCH; old_try = old_try->next_peer)
+ continue;
+ gcc_assert (old_try->type == ERT_TRY);
+ new_try = gen_eh_region_try (new_outer);
+ new_try->tree_label = old_try->tree_label;
+ new_try->may_contain_throw = old_try->may_contain_throw;
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file, "Copying try-catch regions. Try: %i to %i\n",
+ old_try->region_number, new_try->region_number);
+ VEC_safe_grow (eh_region, gc, cfun->eh->region_array,
+ cfun->eh->last_region_number + 1);
+ VEC_replace (eh_region, cfun->eh->region_array, new_try->region_number, new_try);
+
+ /* In order to keep CATCH list in order, we need to copy in reverse order. */
+ for (r = old_try->u.eh_try.last_catch; r->type == ERT_CATCH; r = r->next_peer)
+ VEC_safe_push (eh_region, heap, catch_list, r);
+
+ while (VEC_length (eh_region, catch_list))
+ {
+ r = VEC_pop (eh_region, catch_list);
+
+ /* Duplicate CATCH. */
+ n = gen_eh_region_catch (new_try, r->u.eh_catch.type_list);
+ n->tree_label = r->tree_label;
+ n->may_contain_throw = r->may_contain_throw;
+ VEC_safe_grow (eh_region, gc, cfun->eh->region_array,
+ cfun->eh->last_region_number + 1);
+ VEC_replace (eh_region, cfun->eh->region_array, n->region_number, n);
+ n->tree_label = r->tree_label;
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file, "Copying try-catch regions. Catch: %i to %i\n",
+ r->region_number, n->region_number);
+ if (r == old)
+ ret = n;
+ }
+ VEC_free (eh_region, heap, catch_list);
+ gcc_assert (ret);
+ return ret;
+}
+
+/* Callback for forach_reachable_handler that push REGION into single VECtor DATA. */
+
+static void
+push_reachable_handler (struct eh_region_d *region, void *data)
+{
+ VEC(eh_region,heap) **trace = (VEC(eh_region,heap) **) data;
+ VEC_safe_push (eh_region, heap, *trace, region);
+}
+
+/* Redirect EH edge E that to NEW_DEST_LABEL.
+ IS_RESX, INLINABLE_CALL and REGION_NMUBER match the parameter of
+ foreach_reachable_handler. */
+
+struct eh_region_d *
+redirect_eh_edge_to_label (edge e, tree new_dest_label, bool is_resx,
+ bool inlinable_call, int region_number)
+{
+ struct eh_region_d *outer;
+ struct eh_region_d *region;
+ VEC (eh_region, heap) * trace = NULL;
+ int i;
+ int start_here = -1;
+ basic_block old_bb = e->dest;
+ struct eh_region_d *old, *r = NULL;
+ bool update_inplace = true;
+ edge_iterator ei;
+ edge e2;
+
+ /* If there is only one EH edge, we don't need to duplicate;
+ just update labels in the tree. */
+ FOR_EACH_EDGE (e2, ei, old_bb->preds)
+ if ((e2->flags & EDGE_EH) && e2 != e)
+ {
+ update_inplace = false;
+ break;
+ }
+
+ region = VEC_index (eh_region, cfun->eh->region_array, region_number);
+ gcc_assert (region);
+
+ foreach_reachable_handler (region_number, is_resx, inlinable_call,
+ push_reachable_handler, &trace);
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ dump_eh_tree (dump_file, cfun);
+ fprintf (dump_file, "Trace: ");
+ for (i = 0; i < (int) VEC_length (eh_region, trace); i++)
+ fprintf (dump_file, " %i", VEC_index (eh_region, trace, i)->region_number);
+ fprintf (dump_file, " inplace: %i\n", update_inplace);
+ }
+
+ if (update_inplace)
+ {
+ /* In easy route just walk trace and update all occurences of the label. */
+ for (i = 0; i < (int) VEC_length (eh_region, trace); i++)
+ {
+ r = VEC_index (eh_region, trace, i);
+ if (r->tree_label && label_to_block (r->tree_label) == old_bb)
+ {
+ r->tree_label = new_dest_label;
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file, "Updating label for region %i\n",
+ r->region_number);
+ }
+ }
+ r = region;