* fold-const.c (hashtab.h): Include.
authorkenner <kenner@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 20 Sep 2001 15:12:54 +0000 (15:12 +0000)
committerkenner <kenner@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 20 Sep 2001 15:12:54 +0000 (15:12 +0000)
(int_const_binop): Remove FORSIZE arg and compute from type; all
callers changed.
Call size_int_type_wide for all single-word constants.
(size_htab_hash, size_htab_eq): New functions.
(size_int_type_wide): Rework to use hash table.
* ggc-common.c (hashtab.h): Include.
(struct d_htab_root): New struct.
(d_htab_roots): New variable.
(ggc_add_deletable_htab, ggc_htab_delete): New functions
(ggc_mark_roots): Handle deletable htabs.
* ggc-page.c (ggc_marked_p): New function.
* ggc-simple.c (ggc_marked_p): Likewise.
* ggc.h: Reformatting throughout.
(ggc_marked_p, ggc_add_deletable_htab): New declarations.
* tree.c (init_obstacks): Make type_hash_table a deletable root.
(type_hash_add): Allocate struct type_hash from GC memory.
(mark_hash_entry, mark_type_hash): Deleted.
(type_hash_marked_p, type_hash_mark): New functions.
* Makefile.in (ggc-common.o, fold-const.o): Include hashtab.h.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@45710 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/Makefile.in
gcc/fold-const.c
gcc/ggc-common.c
gcc/ggc-page.c
gcc/ggc-simple.c
gcc/ggc.h
gcc/tree.c

index 587e5d9..b8e3ab8 100644 (file)
@@ -1,3 +1,26 @@
+Thu Sep 20 09:00:27 2001  Richard Kenner  <kenner@vlsi1.ultra.nyu.edu>
+
+       * fold-const.c (hashtab.h): Include.
+       (int_const_binop): Remove FORSIZE arg and compute from type; all
+       callers changed.
+       Call size_int_type_wide for all single-word constants.
+       (size_htab_hash, size_htab_eq): New functions.
+       (size_int_type_wide): Rework to use hash table.
+       * ggc-common.c (hashtab.h): Include.
+       (struct d_htab_root): New struct.
+       (d_htab_roots): New variable.
+       (ggc_add_deletable_htab, ggc_htab_delete): New functions
+       (ggc_mark_roots): Handle deletable htabs.
+       * ggc-page.c (ggc_marked_p): New function.
+       * ggc-simple.c (ggc_marked_p): Likewise.
+       * ggc.h: Reformatting throughout.
+       (ggc_marked_p, ggc_add_deletable_htab): New declarations.
+       * tree.c (init_obstacks): Make type_hash_table a deletable root.
+       (type_hash_add): Allocate struct type_hash from GC memory.
+       (mark_hash_entry, mark_type_hash): Deleted.
+       (type_hash_marked_p, type_hash_mark): New functions.
+       * Makefile.in (ggc-common.o, fold-const.o): Include hashtab.h.
+
 Thu Sep 20 12:49:34 2001  J"orn Rennecke <amylaar@redhat.com>
 
        * sh.c (shiftcosts): Don't use shiftcosts array for modes wider
index 57f29c5..db4dfcd 100644 (file)
@@ -1310,7 +1310,7 @@ dumpvers: dumpvers.c
 version.o: version.c version.h
 
 ggc-common.o: ggc-common.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(TREE_H) \
-       flags.h $(GGC_H) varray.h hash.h $(TM_P_H)
+       flags.h $(GGC_H) varray.h hash.h $(HASHTAB_H) $(TM_P_H)
 
 ggc-simple.o: ggc-simple.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(TREE_H) flags.h \
        $(GGC_H) varray.h $(TIMEVAR_H) $(TM_P_H)
@@ -1346,8 +1346,8 @@ tree.o : tree.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) flags.h function.h toplev.h \
 print-tree.o : print-tree.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) $(GGC_H)
 stor-layout.o : stor-layout.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) flags.h \
    function.h $(EXPR_H) $(RTL_H) toplev.h $(GGC_H) $(TM_P_H)
-fold-const.o : fold-const.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) flags.h toplev.h \
-   $(EXPR_H) $(RTL_H) $(GGC_H) $(TM_P_H)
+fold-const.o : fold-const.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) flags.h \
+   toplev.h $(HASHTAB_H) $(EXPR_H) $(RTL_H) $(GGC_H) $(TM_P_H)
 diagnostic.o : diagnostic.c diagnostic.h real.h diagnostic.def \
    $(CONFIG_H) $(SYSTEM_H) $(TREE_H) $(TM_P_H) flags.h $(GGC_H) \
    input.h toplev.h intl.h
index 7cefaea..b4c60a4 100644 (file)
@@ -51,6 +51,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "tm_p.h"
 #include "toplev.h"
 #include "ggc.h"
+#include "hashtab.h"
 
 static void encode             PARAMS ((HOST_WIDE_INT *,
                                         unsigned HOST_WIDE_INT,
@@ -65,9 +66,11 @@ static tree negate_expr              PARAMS ((tree));
 static tree split_tree         PARAMS ((tree, enum tree_code, tree *, tree *,
                                         int));
 static tree associate_trees    PARAMS ((tree, tree, enum tree_code, tree));
-static tree int_const_binop    PARAMS ((enum tree_code, tree, tree, int, int));
+static tree int_const_binop    PARAMS ((enum tree_code, tree, tree, int));
 static void const_binop_1      PARAMS ((PTR));
 static tree const_binop                PARAMS ((enum tree_code, tree, tree, int));
+static hashval_t size_htab_hash        PARAMS ((const void *));
+static int size_htab_eq                PARAMS ((const void *, const void *));
 static void fold_convert_1     PARAMS ((PTR));
 static tree fold_convert       PARAMS ((tree, tree));
 static enum tree_code invert_tree_comparison PARAMS ((enum tree_code));
@@ -1478,14 +1481,13 @@ associate_trees (t1, t2, code, type)
 /* Combine two integer constants ARG1 and ARG2 under operation CODE
    to produce a new constant.
 
-   If NOTRUNC is nonzero, do not truncate the result to fit the data type.
-   If FORSIZE is nonzero, compute overflow for unsigned types.  */
+   If NOTRUNC is nonzero, do not truncate the result to fit the data type.  */
 
 static tree
-int_const_binop (code, arg1, arg2, notrunc, forsize)
+int_const_binop (code, arg1, arg2, notrunc)
      enum tree_code code;
      register tree arg1, arg2;
-     int notrunc, forsize;
+     int notrunc;
 {
   unsigned HOST_WIDE_INT int1l, int2l;
   HOST_WIDE_INT int1h, int2h;
@@ -1494,7 +1496,10 @@ int_const_binop (code, arg1, arg2, notrunc, forsize)
   unsigned HOST_WIDE_INT garbagel;
   HOST_WIDE_INT garbageh;
   register tree t;
-  int uns = TREE_UNSIGNED (TREE_TYPE (arg1));
+  tree type = TREE_TYPE (arg1);
+  int uns = TREE_UNSIGNED (type);
+  int is_sizetype
+    = (TREE_CODE (type) == INTEGER_TYPE && TYPE_IS_SIZETYPE (type));
   int overflow = 0;
   int no_overflow = 0;
 
@@ -1527,7 +1532,7 @@ int_const_binop (code, arg1, arg2, notrunc, forsize)
       /* It's unclear from the C standard whether shifts can overflow.
         The following code ignores overflow; perhaps a C standard
         interpretation ruling is needed.  */
-      lshift_double (int1l, int1h, int2l, TYPE_PRECISION (TREE_TYPE (arg1)),
+      lshift_double (int1l, int1h, int2l, TYPE_PRECISION (type),
                     &low, &hi, !uns);
       no_overflow = 1;
       break;
@@ -1535,7 +1540,7 @@ int_const_binop (code, arg1, arg2, notrunc, forsize)
     case RROTATE_EXPR:
       int2l = - int2l;
     case LROTATE_EXPR:
-      lrotate_double (int1l, int1h, int2l, TYPE_PRECISION (TREE_TYPE (arg1)),
+      lrotate_double (int1l, int1h, int2l, TYPE_PRECISION (type),
                      &low, &hi);
       break;
 
@@ -1583,8 +1588,7 @@ int_const_binop (code, arg1, arg2, notrunc, forsize)
          low = 1, hi = 0;
          break;
        }
-      overflow = div_and_round_double (code, uns,
-                                      int1l, int1h, int2l, int2h,
+      overflow = div_and_round_double (code, uns, int1l, int1h, int2l, int2h,
                                       &low, &hi, &garbagel, &garbageh);
       break;
 
@@ -1632,9 +1636,14 @@ int_const_binop (code, arg1, arg2, notrunc, forsize)
       abort ();
     }
 
-  if (forsize && hi == 0 && low < 10000
+  /* If this is for a sizetype, can be represented as one (signed)
+     HOST_WIDE_INT word, and doesn't overflow, use size_int since it caches
+     constants.  */
+  if (is_sizetype
+      && ((hi == 0 && (HOST_WIDE_INT) low >= 0)
+         || (hi == -1 && (HOST_WIDE_INT) low < 0))
       && overflow == 0 && ! TREE_OVERFLOW (arg1) && ! TREE_OVERFLOW (arg2))
-    return size_int_type_wide (low, TREE_TYPE (arg1));
+    return size_int_type_wide (low, type);
   else
     {
       t = build_int_2 (low, hi);
@@ -1642,14 +1651,16 @@ int_const_binop (code, arg1, arg2, notrunc, forsize)
     }
 
   TREE_OVERFLOW (t)
-    = ((notrunc ? (!uns || forsize) && overflow
-       : force_fit_type (t, (!uns || forsize) && overflow) && ! no_overflow)
+    = ((notrunc
+       ? (!uns || is_sizetype) && overflow
+       : (force_fit_type (t, (!uns || is_sizetype) && overflow)
+          && ! no_overflow))
        | TREE_OVERFLOW (arg1)
        | TREE_OVERFLOW (arg2));
 
   /* If we're doing a size calculation, unsigned arithmetic does overflow.
      So check if force_fit_type truncated the value.  */
-  if (forsize
+  if (is_sizetype
       && ! TREE_OVERFLOW (t)
       && (TREE_INT_CST_HIGH (t) != hi
          || TREE_INT_CST_LOW (t) != low))
@@ -1740,7 +1751,7 @@ const_binop (code, arg1, arg2, notrunc)
   STRIP_NOPS (arg2);
 
   if (TREE_CODE (arg1) == INTEGER_CST)
-    return int_const_binop (code, arg1, arg2, notrunc, 0);
+    return int_const_binop (code, arg1, arg2, notrunc);
 
 #if ! defined (REAL_IS_NOT_DOUBLE) || defined (REAL_ARITHMETIC)
   if (TREE_CODE (arg1) == REAL_CST)
@@ -1865,6 +1876,39 @@ const_binop (code, arg1, arg2, notrunc)
     }
   return 0;
 }
+
+/* These are the hash table functions for the hash table of INTEGER_CST
+   nodes of a sizetype.  */
+
+/* Return the hash code code X, an INTEGER_CST.  */
+
+static hashval_t
+size_htab_hash (x)
+     const void *x;
+{
+  tree t = (tree) x;
+
+  return (TREE_INT_CST_HIGH (t) ^ TREE_INT_CST_LOW (t)
+         ^ (hashval_t) ((long) TREE_TYPE (t) >> 3)
+         ^ (TREE_OVERFLOW (t) << 20));
+}
+
+/* Return non-zero if the value represented by *X (an INTEGER_CST tree node)
+   is the same as that given by *Y, which is the same.  */
+
+static int
+size_htab_eq (x, y)
+     const void *x;
+     const void *y;
+{
+  tree xt = (tree) x;
+  tree yt = (tree) y;
+
+  return (TREE_INT_CST_HIGH (xt) == TREE_INT_CST_HIGH (yt)
+         && TREE_INT_CST_LOW (xt) == TREE_INT_CST_LOW (yt)
+         && TREE_TYPE (xt) == TREE_TYPE (yt)
+         && TREE_OVERFLOW (xt) == TREE_OVERFLOW (yt));
+}
 \f
 /* Return an INTEGER_CST with value whose low-order HOST_BITS_PER_WIDE_INT
    bits are given by NUMBER and of the sizetype represented by KIND.  */
@@ -1884,40 +1928,38 @@ size_int_type_wide (number, type)
      HOST_WIDE_INT number;
      tree type;
 {
-  /* Type-size nodes already made for small sizes.  */
-  static tree size_table[2048 + 1];
-  static int init_p = 0;
-  tree t;
+  static htab_t size_htab = 0;
+  static tree new_const = 0;
+  PTR *slot;
 
-  if (! init_p)
+  if (size_htab == 0)
     {
-      ggc_add_tree_root ((tree *) size_table,
-                        sizeof size_table / sizeof (tree));
-      init_p = 1;
+      size_htab = htab_create (1024, size_htab_hash, size_htab_eq, NULL);
+      ggc_add_deletable_htab (size_htab, NULL, NULL);
+      new_const = make_node (INTEGER_CST);
+      ggc_add_tree_root (&new_const, 1);
     }
 
-  /* If this is a positive number that fits in the table we use to hold
-     cached entries, see if it is already in the table and put it there
-     if not.  */
-  if (number >= 0 && number < (int) ARRAY_SIZE (size_table))
+  /* Adjust NEW_CONST to be the constant we want.  If it's already in the
+     hash table, we return the value from the hash table.  Otherwise, we
+     place that in the hash table and make a new node for the next time.  */
+  TREE_INT_CST_LOW (new_const) = number;
+  TREE_INT_CST_HIGH (new_const) = number < 0 ? -1 : 0;
+  TREE_TYPE (new_const) = type;
+  TREE_OVERFLOW (new_const) = TREE_CONSTANT_OVERFLOW (new_const)
+    = force_fit_type (new_const, 0);
+
+  slot = htab_find_slot (size_htab, new_const, INSERT);
+  if (*slot == 0)
     {
-      if (size_table[number] != 0)
-       for (t = size_table[number]; t != 0; t = TREE_CHAIN (t))
-         if (TREE_TYPE (t) == type)
-           return t;
-
-      t = build_int_2 (number, 0);
-      TREE_TYPE (t) = type;
-      TREE_CHAIN (t) = size_table[number];
-      size_table[number] = t;
+      tree t = new_const;
 
+      *slot = (PTR) new_const;
+      new_const = make_node (INTEGER_CST);
       return t;
     }
-
-  t = build_int_2 (number, number < 0 ? -1 : 0);
-  TREE_TYPE (t) = type;
-  TREE_OVERFLOW (t) = TREE_CONSTANT_OVERFLOW (t) = force_fit_type (t, 0);
-  return t;
+  else
+    return (tree) *slot;
 }
 
 /* Combine operands OP1 and OP2 with arithmetic operation CODE.  CODE
@@ -1949,7 +1991,7 @@ size_binop (code, arg0, arg1)
        return arg1;
 
       /* Handle general case of two integer constants.  */
-      return int_const_binop (code, arg0, arg1, 0, 1);
+      return int_const_binop (code, arg0, arg1, 0);
     }
 
   if (arg0 == error_mark_node || arg1 == error_mark_node)
index fe7cbe5..154d47b 100644 (file)
@@ -27,6 +27,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "tree.h"
 #include "tm_p.h"
 #include "hash.h"
+#include "hashtab.h"
 #include "varray.h"
 #include "ggc.h"
 
@@ -47,9 +48,10 @@ static void ggc_mark_tree_ptr PARAMS ((void *));
 static void ggc_mark_rtx_varray_ptr PARAMS ((void *));
 static void ggc_mark_tree_varray_ptr PARAMS ((void *));
 static void ggc_mark_tree_hash_table_ptr PARAMS ((void *));
+static int ggc_htab_delete PARAMS ((void **, void *));
 static void ggc_mark_trees PARAMS ((void));
 static bool ggc_mark_tree_hash_table_entry PARAMS ((struct hash_entry *,
-                                                      hash_table_key));
+                                                   hash_table_key));
 
 /* Maintain global roots that are preserved during GC.  */
 
@@ -166,12 +168,79 @@ ggc_del_root (base)
   abort();
 }
 
+/* Add a hash table to be scanned when all roots have been processed.  We
+   delete any entry in the table that has not been marked.  */
+
+struct d_htab_root
+{
+  struct d_htab_root *next;
+  htab_t htab;
+  ggc_htab_marked_p marked_p;
+  ggc_htab_mark mark;
+};
+
+static struct d_htab_root *d_htab_roots;
+
+/* Add X, an htab, to a list of htabs that contain objects which are allocated
+   from GC memory.  Once all other roots are marked, we check each object in
+   the htab to see if it has already been marked.  If not, it is deleted.
+
+   MARKED_P, if specified, is a function that returns 1 if the entry is to
+   be considered as "marked".  If not present, the data structure pointed to
+   by the htab slot is tested.  This function should be supplied if some
+   other object (such as something pointed to by that object) should be tested
+   in which case the function tests whether that object (or objects) are
+   marked (using ggc_marked_p) and returns nonzero if it is.
+
+   MARK, if specified, is a function that is passed the contents of a slot
+   that has been determined to have been "marked" (via the above function)
+   and marks any other objects pointed to by that object.  For example,
+   we might have a hash table of memory attribute blocks, which are pointed
+   to by a MEM RTL but have a pointer to a DECL.  MARKED_P in that case will
+   not be specified because we want to know if the attribute block is pointed
+   to by the MEM, but MARK must be specified because if the block has been
+   marked, we need to mark the DECL.  */
+
+void
+ggc_add_deletable_htab (x, marked_p, mark)
+     PTR x;
+     ggc_htab_marked_p marked_p;
+     ggc_htab_mark mark;
+{
+  struct d_htab_root *r
+    = (struct d_htab_root *) xmalloc (sizeof (struct d_htab_root));
+
+  r->next = d_htab_roots;
+  r->htab = (htab_t) x;
+  r->marked_p = marked_p ? marked_p : ggc_marked_p;
+  r->mark = mark;
+  d_htab_roots = r;
+}
+
+/* Process a slot of an htab by deleting it if it has not been marked.  */
+
+static int
+ggc_htab_delete (slot, info)
+     void **slot;
+     void *info;
+{
+  struct d_htab_root *r = (struct d_htab_root *) info;
+
+  if (! (*r->marked_p) (*slot))
+    htab_clear_slot (r->htab, slot);
+  else if (r->mark)
+    (*r->mark) (*slot);
+
+  return 1;
+}
+
 /* Iterate through all registered roots and mark each element.  */
 
 void
 ggc_mark_roots ()
 {
-  struct ggc_root* x;
+  struct ggc_root *x;
+  struct d_htab_root *y;
   
   VARRAY_TREE_INIT (ggc_pending_trees, 4096, "ggc_pending_trees");
 
@@ -189,6 +258,16 @@ ggc_mark_roots ()
   /* Mark all the queued up trees, and their children.  */
   ggc_mark_trees ();
   VARRAY_FREE (ggc_pending_trees);
+
+  /* Now scan all hash tables that have objects which are to be deleted if
+     they are not already marked.  Since these may mark more trees, we need
+     to reinitialize that varray.  */
+  VARRAY_TREE_INIT (ggc_pending_trees, 1024, "ggc_pending_trees");
+
+  for (y = d_htab_roots; y != NULL; y = y->next)
+    htab_traverse (y->htab, ggc_htab_delete, (PTR) y);
+  ggc_mark_trees ();
+  VARRAY_FREE (ggc_pending_trees);
 }
 
 /* R had not been previously marked, but has now been marked via
@@ -463,7 +542,7 @@ ggc_mark_tree_varray (v)
       ggc_mark_tree (VARRAY_TREE (v, i));
 }
 
-/* Mark the hash table-entry HE.  It's key field is really a tree.  */
+/* Mark the hash table-entry HE.  Its key field is really a tree.  */
 
 static bool
 ggc_mark_tree_hash_table_entry (he, k)
index b731b29..60517ae 100644 (file)
@@ -1001,6 +1001,35 @@ ggc_set_mark (p)
   return 0;
 }
 
+/* Return 1 if P has been marked, zero otherwise. 
+   P must have been allocated by the GC allocator; it mustn't point to
+   static objects, stack variables, or memory allocated with malloc.  */
+
+int
+ggc_marked_p (p)
+     const void *p;
+{
+  page_entry *entry;
+  unsigned bit, word;
+  unsigned long mask;
+
+  /* Look up the page on which the object is alloced.  If the object
+     wasn't allocated by the collector, we'll probably die.  */
+  entry = lookup_page_table_entry (p);
+#ifdef ENABLE_CHECKING
+  if (entry == NULL)
+    abort ();
+#endif
+
+  /* Calculate the index of the object on the page; this is its bit
+     position in the in_use_p bitmap.  */
+  bit = (((const char *) p) - entry->page) / OBJECT_SIZE (entry->order);
+  word = bit / HOST_BITS_PER_LONG;
+  mask = (unsigned long) 1 << (bit % HOST_BITS_PER_LONG);
+  
+  return entry->in_use_p[word] & mask;
+}
+
 /* Return the size of the gc-able object P.  */
 
 size_t
index 496508a..81d2c36 100644 (file)
@@ -228,6 +228,23 @@ ggc_set_mark (p)
   return 0;
 }
 
+/* Return 1 if P has been marked, zero otherwise.  */
+
+int
+ggc_marked_p (p)
+     const void *p;
+{
+  struct ggc_mem *x;
+
+  x = (struct ggc_mem *) ((const char *)p - offsetof (struct ggc_mem, u));
+#ifdef GGC_ALWAYS_VERIFY
+  if (! tree_lookup (x))
+    abort ();
+#endif
+
+   return x->mark;
+}
+
 /* Return the size of the gc-able object P.  */
 
 size_t
index be137e7..fe3290b 100644 (file)
--- a/gcc/ggc.h
+++ b/gcc/ggc.h
@@ -47,23 +47,39 @@ extern const char digit_vector[];   /* "0" .. "9" */
 extern varray_type ggc_pending_trees;
 
 /* Manipulate global roots that are needed between calls to gc.  */
-void ggc_add_root PARAMS ((void *base, int nelt, int size, void (*)(void *)));
-void ggc_add_rtx_root PARAMS ((struct rtx_def **, int nelt));
-void ggc_add_tree_root PARAMS ((union tree_node **, int nelt));
-void ggc_add_rtx_varray_root PARAMS ((struct varray_head_tag **, int nelt));
-void ggc_add_tree_varray_root PARAMS ((struct varray_head_tag **, int nelt));
-void ggc_add_tree_hash_table_root PARAMS ((struct hash_table **, int nelt));
-void ggc_del_root PARAMS ((void *base));
+extern void ggc_add_root               PARAMS ((void *base, int nelt,
+                                                int size, void (*)(void *)));
+extern void ggc_add_rtx_root           PARAMS ((struct rtx_def **, int nelt));
+extern void ggc_add_tree_root          PARAMS ((union tree_node **,
+                                                int nelt));
+extern void ggc_add_rtx_varray_root    PARAMS ((struct varray_head_tag **,
+                                                int nelt));
+extern void ggc_add_tree_varray_root   PARAMS ((struct varray_head_tag **,
+                                                int nelt));
+extern void ggc_add_tree_hash_table_root PARAMS ((struct hash_table **,
+                                                 int nelt));
+extern void ggc_del_root               PARAMS ((void *base));
+
+/* Types used for mark test and marking functions, if specified, in call
+   below.  */
+typedef int (*ggc_htab_marked_p) PARAMS ((const void *));
+typedef void (*ggc_htab_mark) PARAMS ((const void *));
+
+/* Add a hash table to be scanned when all roots have been processed.  We
+   delete any entry in the table that has not been marked.  The argument is
+   really htab_t.  */
+extern void ggc_add_deletable_htab     PARAMS ((PTR, ggc_htab_marked_p,
+                                                ggc_htab_mark));
 
 /* Mark nodes from the gc_add_root callback.  These functions follow
    pointers to mark other objects too.  */
-extern void ggc_mark_rtx_varray PARAMS ((struct varray_head_tag *));
-extern void ggc_mark_tree_varray PARAMS ((struct varray_head_tag *));
-extern void ggc_mark_tree_hash_table PARAMS ((struct hash_table *));
-extern void ggc_mark_roots PARAMS ((void));
+extern void ggc_mark_rtx_varray                PARAMS ((struct varray_head_tag *));
+extern void ggc_mark_tree_varray       PARAMS ((struct varray_head_tag *));
+extern void ggc_mark_tree_hash_table   PARAMS ((struct hash_table *));
+extern void ggc_mark_roots             PARAMS ((void));
 
-extern void ggc_mark_rtx_children PARAMS ((struct rtx_def *));
-extern void ggc_mark_rtvec_children PARAMS ((struct rtvec_def *));
+extern void ggc_mark_rtx_children      PARAMS ((struct rtx_def *));
+extern void ggc_mark_rtvec_children    PARAMS ((struct rtvec_def *));
 
 /* If EXPR is not NULL and previously unmarked, mark it and evaluate
    to true.  Otherwise evaluate to false.  */
@@ -108,23 +124,23 @@ extern void ggc_mark_rtvec_children PARAMS ((struct rtvec_def *));
 /* A GC implementation must provide these functions.  */
 
 /* Initialize the garbage collector.   */
-extern void init_ggc PARAMS ((void));
-extern void init_stringpool PARAMS ((void));
+extern void init_ggc           PARAMS ((void));
+extern void init_stringpool    PARAMS ((void));
 
 /* Start a new GGC context.  Memory allocated in previous contexts
    will not be collected while the new context is active.  */
-extern void ggc_push_context PARAMS ((void));
+extern void ggc_push_context   PARAMS ((void));
 
 /* Finish a GC context.  Any uncollected memory in the new context
    will be merged with the old context.  */
-extern void ggc_pop_context PARAMS ((void));
+extern void ggc_pop_context    PARAMS ((void));
 
 /* Allocation.  */
 
 /* The internal primitive.  */
-void *ggc_alloc PARAMS ((size_t));
+extern void *ggc_alloc         PARAMS ((size_t));
 /* Like ggc_alloc, but allocates cleared memory.  */
-void *ggc_alloc_cleared PARAMS ((size_t));
+extern void *ggc_alloc_cleared PARAMS ((size_t));
 
 #define ggc_alloc_rtx(NSLOTS)                                            \
   ((struct rtx_def *) ggc_alloc (sizeof (struct rtx_def)                 \
@@ -139,27 +155,33 @@ void *ggc_alloc_cleared PARAMS ((size_t));
 /* Allocate a gc-able string, and fill it with LENGTH bytes from CONTENTS.
    If LENGTH is -1, then CONTENTS is assumed to be a
    null-terminated string and the memory sized accordingly.  */
-const char *ggc_alloc_string PARAMS ((const char *contents, int length));
+extern const char *ggc_alloc_string    PARAMS ((const char *contents,
+                                                int length));
 
 /* Make a copy of S, in GC-able memory.  */
 #define ggc_strdup(S) ggc_alloc_string((S), -1)
 
 /* Invoke the collector.  Garbage collection occurs only when this
    function is called, not during allocations.  */
-void ggc_collect PARAMS ((void));
+extern void ggc_collect                        PARAMS ((void));
 
 /* Actually set the mark on a particular region of memory, but don't
    follow pointers.  This function is called by ggc_mark_*.  It
    returns zero if the object was not previously marked; non-zero if
    the object was already marked, or if, for any other reason,
    pointers in this data structure should not be traversed.  */
-int ggc_set_mark PARAMS ((const void *));
+extern int ggc_set_mark                        PARAMS ((const void *));
+
+/* Return 1 if P has been marked, zero otherwise. 
+   P must have been allocated by the GC allocator; it mustn't point to
+   static objects, stack variables, or memory allocated with malloc.  */
+extern int ggc_marked_p                        PARAMS ((const void *));
 
 /* Callbacks to the languages.  */
 
 /* This is the language's opportunity to mark nodes held through
    the lang_specific hooks in the tree.  */
-void lang_mark_tree PARAMS ((union tree_node *));
+extern void lang_mark_tree             PARAMS ((union tree_node *));
 
 /* The FALSE_LABEL_STACK, declared in except.h, has language-dependent
    semantics.  If a front-end needs to mark the false label stack, it
@@ -169,12 +191,12 @@ extern void (*lang_mark_false_label_stack) PARAMS ((struct label_node *));
 
 /* Mark functions for various structs scattered about.  */
 
-void mark_eh_status PARAMS ((struct eh_status *));
-void mark_emit_status PARAMS ((struct emit_status *));
-void mark_expr_status PARAMS ((struct expr_status *));
-void mark_stmt_status PARAMS ((struct stmt_status *));
-void mark_varasm_status PARAMS ((struct varasm_status *));
-void mark_optab PARAMS ((void *));
+void mark_eh_status                    PARAMS ((struct eh_status *));
+void mark_emit_status                  PARAMS ((struct emit_status *));
+void mark_expr_status                  PARAMS ((struct expr_status *));
+void mark_stmt_status                  PARAMS ((struct stmt_status *));
+void mark_varasm_status                        PARAMS ((struct varasm_status *));
+void mark_optab                                PARAMS ((void *));
 
 /* Statistics.  */
 
@@ -203,12 +225,12 @@ typedef struct ggc_statistics
 } ggc_statistics;
 
 /* Return the number of bytes allocated at the indicated address.  */
-size_t ggc_get_size PARAMS ((const void *));
+extern size_t ggc_get_size             PARAMS ((const void *));
 
 /* Used by the various collectors to gather and print statistics that
    do not depend on the collector in use.  */
-void ggc_print_common_statistics PARAMS ((FILE *, ggc_statistics *));
+extern void ggc_print_common_statistics PARAMS ((FILE *, ggc_statistics *));
 
 /* Print allocation statistics.  */
-extern void ggc_print_statistics PARAMS ((void));
-void stringpool_statistics PARAMS ((void));
+extern void ggc_print_statistics       PARAMS ((void));
+extern void stringpool_statistics      PARAMS ((void));
index 14d4807..731791c 100644 (file)
@@ -158,12 +158,12 @@ htab_t type_hash_table;
 static void build_real_from_int_cst_1 PARAMS ((PTR));
 static void set_type_quals PARAMS ((tree, int));
 static void append_random_chars PARAMS ((char *));
-static void mark_type_hash PARAMS ((void *));
 static int type_hash_eq PARAMS ((const void*, const void*));
 static unsigned int type_hash_hash PARAMS ((const void*));
 static void print_type_hash_statistics PARAMS((void));
-static int mark_hash_entry PARAMS((void **, void *));
 static void finish_vector_type PARAMS((tree));
+static int type_hash_marked_p PARAMS ((const void *));
+static void type_hash_mark PARAMS ((const void *));
 static int mark_tree_hashtable_entry PARAMS((void **, void *));
 
 /* If non-null, these are language-specific helper functions for
@@ -225,7 +225,8 @@ init_obstacks ()
   /* Initialize the hash table of types.  */
   type_hash_table = htab_create (TYPE_HASH_INITIAL_SIZE, type_hash_hash,
                                 type_hash_eq, 0);
-  ggc_add_root (&type_hash_table, 1, sizeof type_hash_table, mark_type_hash);
+  ggc_add_deletable_htab (type_hash_table, type_hash_marked_p,
+                         type_hash_mark);
   ggc_add_tree_root (global_trees, TI_MAX);
   ggc_add_tree_root (integer_types, itk_none);
 
@@ -3186,7 +3187,7 @@ type_hash_add (hashcode, type)
   struct type_hash *h;
   void **loc;
 
-  h = (struct type_hash *) permalloc (sizeof (struct type_hash));
+  h = (struct type_hash *) ggc_alloc (sizeof (struct type_hash));
   h->hash = hashcode;
   h->type = type;
   loc = htab_find_slot_with_hash (type_hash_table, h, hashcode, INSERT);
@@ -3217,6 +3218,8 @@ type_hash_canon (hashcode, type)
   if (debug_no_type_hash)
     return type;
 
+  /* See if the type is in the hash table already.  If so, return it.
+     Otherwise, add the type.  */
   t1 = type_hash_lookup (hashcode, type);
   if (t1 != 0)
     {
@@ -3226,37 +3229,29 @@ type_hash_canon (hashcode, type)
 #endif
       return t1;
     }
-
-  /* If this is a permanent type, record it for later reuse.  */
-  type_hash_add (hashcode, type);
-
-  return type;
+  else
+    {
+      type_hash_add (hashcode, type);
+      return type;
+    }
 }
 
-/* Callback function for htab_traverse.  */
+/* See if the data pointed to by the type hash table is marked.  */
 
 static int
-mark_hash_entry (entry, param)
-     void **entry;
-     void *param ATTRIBUTE_UNUSED;
+type_hash_marked_p (p)
+     const void *p;
 {
-  struct type_hash *p = *(struct type_hash **) entry;
-
-  ggc_mark_tree (p->type);
-
-  /* Continue scan.  */
-  return 1;
+  return ggc_marked_p (((struct type_hash *) p)->type);
 }
 
-/* Mark ARG (which is really a htab_t *) for GC.  */
+/* Mark the entry in the type hash table the type it points to is marked. */
 
 static void
-mark_type_hash (arg)
-     void *arg;
+type_hash_mark (p)
+     const void *p;
 {
-  htab_t t = *(htab_t *) arg;
-
-  htab_traverse (t, mark_hash_entry, 0);
+  ggc_mark (p);
 }
 
 /* Mark the hashtable slot pointed to by ENTRY (which is really a