except.c (remove_eh_handler_and_replace): Break out from ...
authorJan Hubicka <jh@suse.cz>
Sat, 4 Apr 2009 17:15:31 +0000 (19:15 +0200)
committerJan Hubicka <hubicka@gcc.gnu.org>
Sat, 4 Apr 2009 17:15:31 +0000 (17:15 +0000)
* except.c (remove_eh_handler_and_replace): Break out from ...
(remove_eh_handler): ... here.
(bring_to_root): New function.
(remove_unreachable_regions): Collect MUST_NOT_THROW, unify runtime
handled ones, bring others to root of tree.

From-SVN: r145545

gcc/ChangeLog
gcc/except.c

index 7239ecf32e1217a82136b1f8f21773b8a9d92dcb..730df1d450a9a5406d2f0d2eed5fc97d0ef4ffaa 100644 (file)
@@ -1,3 +1,11 @@
+2009-04-04  Jan Hubicka  <jh@suse.cz>
+
+       * except.c (remove_eh_handler_and_replace): Break out from ...
+       (remove_eh_handler): ... here.
+       (bring_to_root): New function.
+       (remove_unreachable_regions): Collect MUST_NOT_THROW, unify runtime
+       handled ones, bring others to root of tree.
+
 2009-04-04  Jan Hubicka  <jh@suse.cz>
 
        * tree-eh.c (tree_empty_eh_handler_p): Pattern match more curefully.
index 64be6afd2c4a0a56221dd00bbd7f6c3f0c5d6182..2651e99f2d46cf0b733fe4f0afce6ba81d5c6fee 100644 (file)
@@ -208,6 +208,7 @@ struct call_site_record GTY(())
 
 DEF_VEC_P(eh_region);
 DEF_VEC_ALLOC_P(eh_region, gc);
+DEF_VEC_ALLOC_P(eh_region, heap);
 
 /* Used to save exception status for each function.  */
 struct eh_status GTY(())
@@ -252,6 +253,8 @@ static int ehl_eq (const void *, const void *);
 static void add_ehl_entry (rtx, struct eh_region *);
 static void remove_exception_handler_label (rtx);
 static void remove_eh_handler (struct eh_region *);
+static void remove_eh_handler_and_replace (struct eh_region *,
+                                          struct eh_region *);
 static int for_each_eh_label_1 (void **, void *);
 
 /* The return value of reachable_next_level.  */
@@ -718,21 +721,42 @@ can_be_reached_by_runtime (sbitmap contains_stmt, struct eh_region *r)
     }
 }
 
+/* Bring region R to the root of tree.  */
+
+static void
+bring_to_root (struct eh_region *r)
+{
+  struct eh_region **pp;
+  struct eh_region *outer = r->outer;
+  if (!r->outer)
+    return;
+  for (pp = &outer->inner; *pp != r; pp = &(*pp)->next_peer)
+    continue;
+  *pp = r->next_peer;
+  r->outer = NULL;
+  r->next_peer = cfun->eh->region_tree;
+  cfun->eh->region_tree = r;
+}
+
 /* Remove all regions whose labels are not reachable.
    REACHABLE is bitmap of all regions that are used by the function
    CONTAINS_STMT is bitmap of all regions that contains stmt (or NULL). */
+
 void
 remove_unreachable_regions (sbitmap reachable, sbitmap contains_stmt)
 {
   int i;
   struct eh_region *r;
+  VEC(eh_region,heap) *must_not_throws = VEC_alloc (eh_region, heap, 16);
+  struct eh_region *local_must_not_throw = NULL;
+  struct eh_region *first_must_not_throw = NULL;
 
   for (i = cfun->eh->last_region_number; i > 0; --i)
     {
       r = VEC_index (eh_region, cfun->eh->region_array, i);
-      if (!r)
+      if (!r || r->region_number != i)
        continue;
-      if (r->region_number == i && !TEST_BIT (reachable, i) && !r->resume)
+      if (!TEST_BIT (reachable, i) && !r->resume)
        {
          bool kill_it = true;
 
@@ -783,11 +807,60 @@ remove_unreachable_regions (sbitmap reachable, sbitmap contains_stmt)
                         r->region_number);
              remove_eh_handler (r);
            }
+         else if (r->type == ERT_MUST_NOT_THROW)
+           {
+             if (!first_must_not_throw)
+               first_must_not_throw = r;
+             VEC_safe_push (eh_region, heap, must_not_throws, r);
+           }
+       }
+      else
+       if (r->type == ERT_MUST_NOT_THROW)
+         {
+           if (!local_must_not_throw)
+             local_must_not_throw = r;
+           if (r->outer)
+             VEC_safe_push (eh_region, heap, must_not_throws, r);
+         }
+    }
+
+  /* MUST_NOT_THROW regions without local handler are all the same; they
+     trigger terminate call in runtime.
+     MUST_NOT_THROW handled locally can differ in debug info associated
+     to std::terminate () call or if one is coming from Java and other
+     from C++ whether they call terminate or abort.  
+
+     We merge all MUST_NOT_THROW regions handled by the run-time into one.
+     We alsobring all local MUST_NOT_THROW regions to the roots of EH tree
+     (since unwinding never continues to the outer region anyway).
+     If MUST_NOT_THROW with local handler is present in the tree, we use
+     that region to merge into, since it will remain in tree anyway;
+     otherwise we use first MUST_NOT_THROW.
+
+     Merging of locally handled regions needs changes to the CFG.  Crossjumping
+     should take care of this, by looking at the actual code and
+     ensuring that the cleanup actions are really the same.  */
+
+  if (local_must_not_throw)
+    first_must_not_throw = local_must_not_throw;
+
+  for (i = 0; VEC_iterate (eh_region, must_not_throws, i, r); i++)
+    {
+      if (!r->label && !r->tree_label && r != first_must_not_throw)
+       {
+         if (dump_file)
+           fprintf (dump_file, "Replacing MUST_NOT_THROW region %i by %i\n",
+                    r->region_number,
+                    first_must_not_throw->region_number);
+         remove_eh_handler_and_replace (r, first_must_not_throw);
        }
+      else
+       bring_to_root (r);
     }
 #ifdef ENABLE_CHECKING
   verify_eh_tree (cfun);
 #endif
+  VEC_free (eh_region, heap, must_not_throws);
 }
 
 /* Return array mapping LABEL_DECL_UID to region such that region's tree_label
@@ -2352,22 +2425,24 @@ remove_exception_handler_label (rtx label)
   htab_clear_slot (crtl->eh.exception_handler_label_map, (void **) slot);
 }
 
-/* Splice REGION from the region tree etc.  */
+/* Splice REGION from the region tree and replace it by REPLACE etc.  */
 
 static void
-remove_eh_handler (struct eh_region *region)
+remove_eh_handler_and_replace (struct eh_region *region,
+                              struct eh_region *replace)
 {
   struct eh_region **pp, **pp_start, *p, *outer, *inner;
   rtx lab;
 
+  outer = region->outer;
   /* For the benefit of efficiently handling REG_EH_REGION notes,
      replace this region in the region array with its containing
      region.  Note that previous region deletions may result in
      multiple copies of this region in the array, so we have a
      list of alternate numbers by which we are known.  */
 
-  outer = region->outer;
-  VEC_replace (eh_region, cfun->eh->region_array, region->region_number, outer);
+  VEC_replace (eh_region, cfun->eh->region_array, region->region_number,
+              replace);
   if (region->aka)
     {
       unsigned i;
@@ -2375,17 +2450,17 @@ remove_eh_handler (struct eh_region *region)
 
       EXECUTE_IF_SET_IN_BITMAP (region->aka, 0, i, bi)
        {
-          VEC_replace (eh_region, cfun->eh->region_array, i, outer);
+          VEC_replace (eh_region, cfun->eh->region_array, i, replace);
        }
     }
 
-  if (outer)
+  if (replace)
     {
-      if (!outer->aka)
-        outer->aka = BITMAP_GGC_ALLOC ();
+      if (!replace->aka)
+        replace->aka = BITMAP_GGC_ALLOC ();
       if (region->aka)
-       bitmap_ior_into (outer->aka, region->aka);
-      bitmap_set_bit (outer->aka, region->region_number);
+       bitmap_ior_into (replace->aka, region->aka);
+      bitmap_set_bit (replace->aka, region->region_number);
     }
 
   if (crtl->eh.built_landing_pads)
@@ -2403,12 +2478,16 @@ remove_eh_handler (struct eh_region *region)
     continue;
   *pp = region->next_peer;
 
+  if (replace)
+    pp_start = &replace->inner;
+  else
+    pp_start = &cfun->eh->region_tree;
   inner = region->inner;
   if (inner)
     {
       for (p = inner; p->next_peer ; p = p->next_peer)
-       p->outer = outer;
-      p->outer = outer;
+       p->outer = replace;
+      p->outer = replace;
 
       p->next_peer = *pp_start;
       *pp_start = inner;
@@ -2442,6 +2521,15 @@ remove_eh_handler (struct eh_region *region)
     }
 }
 
+/* Splice REGION from the region tree and replace it by the outer region
+   etc.  */
+
+static void
+remove_eh_handler (struct eh_region *region)
+{
+  remove_eh_handler_and_replace (region, region->outer);
+}
+
 /* LABEL heads a basic block that is about to be deleted.  If this
    label corresponds to an exception region, we may be able to
    delete the region.  */