* tree.c (save_expr): Allow either side of a dyadic operand to be
[official-gcc.git] / gcc / ggc-common.c
blobf353617f4f725988e5fe7ec65725a09dccc4eb36
1 /* Simple garbage collection for the GNU compiler.
2 Copyright (C) 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
4 This file is part of GCC.
6 GCC is free software; you can redistribute it and/or modify it under
7 the terms of the GNU General Public License as published by the Free
8 Software Foundation; either version 2, or (at your option) any later
9 version.
11 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 for more details.
16 You should have received a copy of the GNU General Public License
17 along with GCC; see the file COPYING. If not, write to the Free
18 Software Foundation, 59 Temple Place - Suite 330, Boston, MA
19 02111-1307, USA. */
21 /* Generic garbage collection (GC) functions and data, not specific to
22 any particular GC implementation. */
24 #include "config.h"
25 #include "system.h"
26 #include "coretypes.h"
27 #include "tm.h"
28 #include "rtl.h"
29 #include "tree.h"
30 #include "tm_p.h"
31 #include "hashtab.h"
32 #include "varray.h"
33 #include "ggc.h"
34 #include "langhooks.h"
35 #ifdef ENABLE_VALGRIND_CHECKING
36 #include <valgrind.h>
37 #else
38 /* Avoid #ifdef:s when we can help it. */
39 #define VALGRIND_DISCARD(x)
40 #endif
42 /* Statistics about the allocation. */
43 static ggc_statistics *ggc_stats;
45 static int ggc_htab_delete PARAMS ((void **, void *));
47 /* Maintain global roots that are preserved during GC. */
49 /* Global roots that are preserved during calls to gc. */
51 struct ggc_root
53 struct ggc_root *next;
54 void *base;
55 int nelt;
56 int size;
57 void (*cb) PARAMS ((void *));
60 static struct ggc_root *roots;
62 /* Add BASE as a new garbage collection root. It is an array of
63 length NELT with each element SIZE bytes long. CB is a
64 function that will be called with a pointer to each element
65 of the array; it is the intention that CB call the appropriate
66 routine to mark gc-able memory for that element. */
68 void
69 ggc_add_root (base, nelt, size, cb)
70 void *base;
71 int nelt, size;
72 void (*cb) PARAMS ((void *));
74 struct ggc_root *x = (struct ggc_root *) xmalloc (sizeof (*x));
76 x->next = roots;
77 x->base = base;
78 x->nelt = nelt;
79 x->size = size;
80 x->cb = cb;
82 roots = x;
85 /* Process a slot of an htab by deleting it if it has not been marked. */
87 static int
88 ggc_htab_delete (slot, info)
89 void **slot;
90 void *info;
92 const struct ggc_cache_tab *r = (const struct ggc_cache_tab *) info;
94 if (! (*r->marked_p) (*slot))
95 htab_clear_slot (*r->base, slot);
96 else
97 (*r->cb) (*slot);
99 return 1;
102 /* Iterate through all registered roots and mark each element. */
104 void
105 ggc_mark_roots ()
107 struct ggc_root *x;
108 const struct ggc_root_tab *const *rt;
109 const struct ggc_root_tab *rti;
110 const struct ggc_cache_tab *const *ct;
111 const struct ggc_cache_tab *cti;
112 size_t i;
114 for (rt = gt_ggc_deletable_rtab; *rt; rt++)
115 for (rti = *rt; rti->base != NULL; rti++)
116 memset (rti->base, 0, rti->stride);
118 for (rt = gt_ggc_rtab; *rt; rt++)
119 for (rti = *rt; rti->base != NULL; rti++)
120 for (i = 0; i < rti->nelt; i++)
121 (*rti->cb)(*(void **)((char *)rti->base + rti->stride * i));
123 for (x = roots; x != NULL; x = x->next)
125 char *elt = x->base;
126 int s = x->size, n = x->nelt;
127 void (*cb) PARAMS ((void *)) = x->cb;
128 int i;
130 for (i = 0; i < n; ++i, elt += s)
131 (*cb)(elt);
134 /* Now scan all hash tables that have objects which are to be deleted if
135 they are not already marked. */
136 for (ct = gt_ggc_cache_rtab; *ct; ct++)
137 for (cti = *ct; cti->base != NULL; cti++)
138 if (*cti->base)
139 htab_traverse (*cti->base, ggc_htab_delete, (PTR) cti);
142 /* Allocate a block of memory, then clear it. */
143 void *
144 ggc_alloc_cleared (size)
145 size_t size;
147 void *buf = ggc_alloc (size);
148 memset (buf, 0, size);
149 return buf;
152 /* Resize a block of memory, possibly re-allocating it. */
153 void *
154 ggc_realloc (x, size)
155 void *x;
156 size_t size;
158 void *r;
159 size_t old_size;
161 if (x == NULL)
162 return ggc_alloc (size);
164 old_size = ggc_get_size (x);
165 if (size <= old_size)
167 /* Mark the unwanted memory as unaccessible. We also need to make
168 the "new" size accessible, since ggc_get_size returns the size of
169 the pool, not the size of the individually allocated object, the
170 size which was previously made accessible. Unfortunately, we
171 don't know that previously allocated size. Without that
172 knowledge we have to lose some initialization-tracking for the
173 old parts of the object. An alternative is to mark the whole
174 old_size as reachable, but that would lose tracking of writes
175 after the end of the object (by small offsets). Discard the
176 handle to avoid handle leak. */
177 VALGRIND_DISCARD (VALGRIND_MAKE_NOACCESS ((char *) x + size,
178 old_size - size));
179 VALGRIND_DISCARD (VALGRIND_MAKE_READABLE (x, size));
180 return x;
183 r = ggc_alloc (size);
185 /* Since ggc_get_size returns the size of the pool, not the size of the
186 individually allocated object, we'd access parts of the old object
187 that were marked invalid with the memcpy below. We lose a bit of the
188 initialization-tracking since some of it may be uninitialized. */
189 VALGRIND_DISCARD (VALGRIND_MAKE_READABLE (x, old_size));
191 memcpy (r, x, old_size);
193 /* The old object is not supposed to be used anymore. */
194 VALGRIND_DISCARD (VALGRIND_MAKE_NOACCESS (x, old_size));
196 return r;
199 /* Like ggc_alloc_cleared, but performs a multiplication. */
200 void *
201 ggc_calloc (s1, s2)
202 size_t s1, s2;
204 return ggc_alloc_cleared (s1 * s2);
207 /* Print statistics that are independent of the collector in use. */
208 #define SCALE(x) ((unsigned long) ((x) < 1024*10 \
209 ? (x) \
210 : ((x) < 1024*1024*10 \
211 ? (x) / 1024 \
212 : (x) / (1024*1024))))
213 #define LABEL(x) ((x) < 1024*10 ? ' ' : ((x) < 1024*1024*10 ? 'k' : 'M'))
215 void
216 ggc_print_common_statistics (stream, stats)
217 FILE *stream;
218 ggc_statistics *stats;
220 int code;
222 /* Set the pointer so that during collection we will actually gather
223 the statistics. */
224 ggc_stats = stats;
226 /* Then do one collection to fill in the statistics. */
227 ggc_collect ();
229 /* Total the statistics. */
230 for (code = 0; code < MAX_TREE_CODES; ++code)
232 stats->total_num_trees += stats->num_trees[code];
233 stats->total_size_trees += stats->size_trees[code];
235 for (code = 0; code < NUM_RTX_CODE; ++code)
237 stats->total_num_rtxs += stats->num_rtxs[code];
238 stats->total_size_rtxs += stats->size_rtxs[code];
241 /* Print the statistics for trees. */
242 fprintf (stream, "\n%-17s%10s %16s %10s\n", "Tree",
243 "Number", "Bytes", "% Total");
244 for (code = 0; code < MAX_TREE_CODES; ++code)
245 if (ggc_stats->num_trees[code])
247 fprintf (stream, "%-17s%10u%16ld%c %10.3f\n",
248 tree_code_name[code],
249 ggc_stats->num_trees[code],
250 SCALE (ggc_stats->size_trees[code]),
251 LABEL (ggc_stats->size_trees[code]),
252 (100 * ((double) ggc_stats->size_trees[code])
253 / ggc_stats->total_size_trees));
255 fprintf (stream,
256 "%-17s%10u%16ld%c\n", "Total",
257 ggc_stats->total_num_trees,
258 SCALE (ggc_stats->total_size_trees),
259 LABEL (ggc_stats->total_size_trees));
261 /* Print the statistics for RTL. */
262 fprintf (stream, "\n%-17s%10s %16s %10s\n", "RTX",
263 "Number", "Bytes", "% Total");
264 for (code = 0; code < NUM_RTX_CODE; ++code)
265 if (ggc_stats->num_rtxs[code])
267 fprintf (stream, "%-17s%10u%16ld%c %10.3f\n",
268 rtx_name[code],
269 ggc_stats->num_rtxs[code],
270 SCALE (ggc_stats->size_rtxs[code]),
271 LABEL (ggc_stats->size_rtxs[code]),
272 (100 * ((double) ggc_stats->size_rtxs[code])
273 / ggc_stats->total_size_rtxs));
275 fprintf (stream,
276 "%-17s%10u%16ld%c\n", "Total",
277 ggc_stats->total_num_rtxs,
278 SCALE (ggc_stats->total_size_rtxs),
279 LABEL (ggc_stats->total_size_rtxs));
281 /* Don't gather statistics any more. */
282 ggc_stats = NULL;