From: kenner Date: Thu, 20 Sep 2001 15:12:54 +0000 (+0000) Subject: * fold-const.c (hashtab.h): Include. X-Git-Tag: upstream/4.9.2~92001 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=15d769aab42c4ea8a8863b8b37dee46c77155be0;p=platform%2Fupstream%2Flinaro-gcc.git * 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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@45710 138bc75d-0d04-0410-961f-82ee72b054a4 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 587e5d9..b8e3ab8 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,26 @@ +Thu Sep 20 09:00:27 2001 Richard Kenner + + * 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 * sh.c (shiftcosts): Don't use shiftcosts array for modes wider diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 57f29c5..db4dfcd 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -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 diff --git a/gcc/fold-const.c b/gcc/fold-const.c index 7cefaea..b4c60a4 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -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)); +} /* 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) diff --git a/gcc/ggc-common.c b/gcc/ggc-common.c index fe7cbe5..154d47b3 100644 --- a/gcc/ggc-common.c +++ b/gcc/ggc-common.c @@ -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) diff --git a/gcc/ggc-page.c b/gcc/ggc-page.c index b731b29..60517ae 100644 --- a/gcc/ggc-page.c +++ b/gcc/ggc-page.c @@ -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 diff --git a/gcc/ggc-simple.c b/gcc/ggc-simple.c index 496508a..81d2c36 100644 --- a/gcc/ggc-simple.c +++ b/gcc/ggc-simple.c @@ -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 diff --git a/gcc/ggc.h b/gcc/ggc.h index be137e7..fe3290b 100644 --- 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)); diff --git a/gcc/tree.c b/gcc/tree.c index 14d4807..731791c 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -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