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. */
32 #include "langhooks.h"
33 #ifdef ENABLE_VALGRIND_CHECKING
36 /* Avoid #ifdef:s when we can help it. */
37 #define VALGRIND_DISCARD(x)
40 /* Statistics about the allocation. */
41 static ggc_statistics
*ggc_stats
;
43 static int ggc_htab_delete
PARAMS ((void **, void *));
45 /* Maintain global roots that are preserved during GC. */
47 /* Global roots that are preserved during calls to gc. */
51 struct ggc_root
*next
;
55 void (*cb
) PARAMS ((void *));
58 static struct ggc_root
*roots
;
60 /* Add BASE as a new garbage collection root. It is an array of
61 length NELT with each element SIZE bytes long. CB is a
62 function that will be called with a pointer to each element
63 of the array; it is the intention that CB call the appropriate
64 routine to mark gc-able memory for that element. */
67 ggc_add_root (base
, nelt
, size
, cb
)
70 void (*cb
) PARAMS ((void *));
72 struct ggc_root
*x
= (struct ggc_root
*) xmalloc (sizeof (*x
));
83 /* Process a slot of an htab by deleting it if it has not been marked. */
86 ggc_htab_delete (slot
, info
)
90 const struct ggc_cache_tab
*r
= (const struct ggc_cache_tab
*) info
;
92 if (! (*r
->marked_p
) (*slot
))
93 htab_clear_slot (*r
->base
, slot
);
100 /* Iterate through all registered roots and mark each element. */
106 const struct ggc_root_tab
*const *rt
;
107 const struct ggc_root_tab
*rti
;
108 const struct ggc_cache_tab
*const *ct
;
109 const struct ggc_cache_tab
*cti
;
112 for (rt
= gt_ggc_deletable_rtab
; *rt
; rt
++)
113 for (rti
= *rt
; rti
->base
!= NULL
; rti
++)
114 memset (rti
->base
, 0, rti
->stride
);
116 for (rt
= gt_ggc_rtab
; *rt
; rt
++)
117 for (rti
= *rt
; rti
->base
!= NULL
; rti
++)
118 for (i
= 0; i
< rti
->nelt
; i
++)
119 (*rti
->cb
)(*(void **)((char *)rti
->base
+ rti
->stride
* i
));
121 for (x
= roots
; x
!= NULL
; x
= x
->next
)
124 int s
= x
->size
, n
= x
->nelt
;
125 void (*cb
) PARAMS ((void *)) = x
->cb
;
128 for (i
= 0; i
< n
; ++i
, elt
+= s
)
132 /* Now scan all hash tables that have objects which are to be deleted if
133 they are not already marked. */
134 for (ct
= gt_ggc_cache_rtab
; *ct
; ct
++)
135 for (cti
= *ct
; cti
->base
!= NULL
; cti
++)
137 htab_traverse (*cti
->base
, ggc_htab_delete
, (PTR
) cti
);
140 /* Allocate a block of memory, then clear it. */
142 ggc_alloc_cleared (size
)
145 void *buf
= ggc_alloc (size
);
146 memset (buf
, 0, size
);
150 /* Resize a block of memory, possibly re-allocating it. */
152 ggc_realloc (x
, size
)
160 return ggc_alloc (size
);
162 old_size
= ggc_get_size (x
);
163 if (size
<= old_size
)
165 /* Mark the unwanted memory as unaccessible. We also need to make
166 the "new" size accessible, since ggc_get_size returns the size of
167 the pool, not the size of the individually allocated object, the
168 size which was previously made accessible. Unfortunately, we
169 don't know that previously allocated size. Without that
170 knowledge we have to lose some initialization-tracking for the
171 old parts of the object. An alternative is to mark the whole
172 old_size as reachable, but that would lose tracking of writes
173 after the end of the object (by small offsets). Discard the
174 handle to avoid handle leak. */
175 VALGRIND_DISCARD (VALGRIND_MAKE_NOACCESS ((char *) x
+ size
,
177 VALGRIND_DISCARD (VALGRIND_MAKE_READABLE (x
, size
));
181 r
= ggc_alloc (size
);
183 /* Since ggc_get_size returns the size of the pool, not the size of the
184 individually allocated object, we'd access parts of the old object
185 that were marked invalid with the memcpy below. We lose a bit of the
186 initialization-tracking since some of it may be uninitialized. */
187 VALGRIND_DISCARD (VALGRIND_MAKE_READABLE (x
, old_size
));
189 memcpy (r
, x
, old_size
);
191 /* The old object is not supposed to be used anymore. */
192 VALGRIND_DISCARD (VALGRIND_MAKE_NOACCESS (x
, old_size
));
197 /* Like ggc_alloc_cleared, but performs a multiplication. */
202 return ggc_alloc_cleared (s1
* s2
);
205 /* Print statistics that are independent of the collector in use. */
206 #define SCALE(x) ((unsigned long) ((x) < 1024*10 \
208 : ((x) < 1024*1024*10 \
210 : (x) / (1024*1024))))
211 #define LABEL(x) ((x) < 1024*10 ? ' ' : ((x) < 1024*1024*10 ? 'k' : 'M'))
214 ggc_print_common_statistics (stream
, stats
)
216 ggc_statistics
*stats
;
220 /* Set the pointer so that during collection we will actually gather
224 /* Then do one collection to fill in the statistics. */
227 /* Total the statistics. */
228 for (code
= 0; code
< MAX_TREE_CODES
; ++code
)
230 stats
->total_num_trees
+= stats
->num_trees
[code
];
231 stats
->total_size_trees
+= stats
->size_trees
[code
];
233 for (code
= 0; code
< NUM_RTX_CODE
; ++code
)
235 stats
->total_num_rtxs
+= stats
->num_rtxs
[code
];
236 stats
->total_size_rtxs
+= stats
->size_rtxs
[code
];
239 /* Print the statistics for trees. */
240 fprintf (stream
, "\n%-17s%10s %16s %10s\n", "Tree",
241 "Number", "Bytes", "% Total");
242 for (code
= 0; code
< MAX_TREE_CODES
; ++code
)
243 if (ggc_stats
->num_trees
[code
])
245 fprintf (stream
, "%-17s%10u%16ld%c %10.3f\n",
246 tree_code_name
[code
],
247 ggc_stats
->num_trees
[code
],
248 SCALE (ggc_stats
->size_trees
[code
]),
249 LABEL (ggc_stats
->size_trees
[code
]),
250 (100 * ((double) ggc_stats
->size_trees
[code
])
251 / ggc_stats
->total_size_trees
));
254 "%-17s%10u%16ld%c\n", "Total",
255 ggc_stats
->total_num_trees
,
256 SCALE (ggc_stats
->total_size_trees
),
257 LABEL (ggc_stats
->total_size_trees
));
259 /* Print the statistics for RTL. */
260 fprintf (stream
, "\n%-17s%10s %16s %10s\n", "RTX",
261 "Number", "Bytes", "% Total");
262 for (code
= 0; code
< NUM_RTX_CODE
; ++code
)
263 if (ggc_stats
->num_rtxs
[code
])
265 fprintf (stream
, "%-17s%10u%16ld%c %10.3f\n",
267 ggc_stats
->num_rtxs
[code
],
268 SCALE (ggc_stats
->size_rtxs
[code
]),
269 LABEL (ggc_stats
->size_rtxs
[code
]),
270 (100 * ((double) ggc_stats
->size_rtxs
[code
])
271 / ggc_stats
->total_size_rtxs
));
274 "%-17s%10u%16ld%c\n", "Total",
275 ggc_stats
->total_num_rtxs
,
276 SCALE (ggc_stats
->total_size_rtxs
),
277 LABEL (ggc_stats
->total_size_rtxs
));
279 /* Don't gather statistics any more. */