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
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
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
21 /* Generic garbage collection (GC) functions and data, not specific to
22 any particular GC implementation. */
26 #include "coretypes.h"
34 #include "langhooks.h"
35 #ifdef ENABLE_VALGRIND_CHECKING
38 /* Avoid #ifdef:s when we can help it. */
39 #define VALGRIND_DISCARD(x)
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. */
53 struct ggc_root *next;
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. */
69 ggc_add_root (base, nelt, size, cb)
72 void (*cb) PARAMS ((void *));
74 struct ggc_root *x = (struct ggc_root *) xmalloc (sizeof (*x));
85 /* Process a slot of an htab by deleting it if it has not been marked. */
88 ggc_htab_delete (slot, 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);
102 /* Iterate through all registered roots and mark each element. */
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;
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)
126 int s = x->size, n = x->nelt;
127 void (*cb) PARAMS ((void *)) = x->cb;
130 for (i = 0; i < n; ++i, elt += s)
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++)
139 htab_traverse (*cti->base, ggc_htab_delete, (PTR) cti);
142 /* Allocate a block of memory, then clear it. */
144 ggc_alloc_cleared (size)
147 void *buf = ggc_alloc (size);
148 memset (buf, 0, size);
152 /* Resize a block of memory, possibly re-allocating it. */
154 ggc_realloc (x, size)
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,
179 VALGRIND_DISCARD (VALGRIND_MAKE_READABLE (x, size));
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));
199 /* Like ggc_alloc_cleared, but performs a multiplication. */
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 \
210 : ((x) < 1024*1024*10 \
212 : (x) / (1024*1024))))
213 #define LABEL(x) ((x) < 1024*10 ? ' ' : ((x) < 1024*1024*10 ? 'k' : 'M'))
216 ggc_print_common_statistics (stream, stats)
218 ggc_statistics *stats;
222 /* Set the pointer so that during collection we will actually gather
226 /* Then do one collection to fill in the statistics. */
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));
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",
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));
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. */