xref: /dflybsd-src/contrib/gcc-4.7/gcc/ggc-common.c (revision 81fc95a5293ee307c688a350a3feb4734aaddbb4)
1e4b17023SJohn Marino /* Simple garbage collection for the GNU compiler.
2e4b17023SJohn Marino    Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
3e4b17023SJohn Marino    2009, 2010 Free Software Foundation, Inc.
4e4b17023SJohn Marino 
5e4b17023SJohn Marino This file is part of GCC.
6e4b17023SJohn Marino 
7e4b17023SJohn Marino GCC is free software; you can redistribute it and/or modify it under
8e4b17023SJohn Marino the terms of the GNU General Public License as published by the Free
9e4b17023SJohn Marino Software Foundation; either version 3, or (at your option) any later
10e4b17023SJohn Marino version.
11e4b17023SJohn Marino 
12e4b17023SJohn Marino GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13e4b17023SJohn Marino WARRANTY; without even the implied warranty of MERCHANTABILITY or
14e4b17023SJohn Marino FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15e4b17023SJohn Marino for more details.
16e4b17023SJohn Marino 
17e4b17023SJohn Marino You should have received a copy of the GNU General Public License
18e4b17023SJohn Marino along with GCC; see the file COPYING3.  If not see
19e4b17023SJohn Marino <http://www.gnu.org/licenses/>.  */
20e4b17023SJohn Marino 
21e4b17023SJohn Marino /* Generic garbage collection (GC) functions and data, not specific to
22e4b17023SJohn Marino    any particular GC implementation.  */
23e4b17023SJohn Marino 
24e4b17023SJohn Marino #include "config.h"
25e4b17023SJohn Marino #include "system.h"
26e4b17023SJohn Marino #include "coretypes.h"
27e4b17023SJohn Marino #include "hashtab.h"
28e4b17023SJohn Marino #include "ggc.h"
29e4b17023SJohn Marino #include "ggc-internal.h"
30e4b17023SJohn Marino #include "diagnostic-core.h"
31e4b17023SJohn Marino #include "params.h"
32e4b17023SJohn Marino #include "hosthooks.h"
33e4b17023SJohn Marino #include "hosthooks-def.h"
34e4b17023SJohn Marino #include "plugin.h"
35e4b17023SJohn Marino #include "vec.h"
36e4b17023SJohn Marino #include "timevar.h"
37e4b17023SJohn Marino 
38e4b17023SJohn Marino /* When set, ggc_collect will do collection.  */
39e4b17023SJohn Marino bool ggc_force_collect;
40e4b17023SJohn Marino 
41e4b17023SJohn Marino /* When true, protect the contents of the identifier hash table.  */
42e4b17023SJohn Marino bool ggc_protect_identifiers = true;
43e4b17023SJohn Marino 
44e4b17023SJohn Marino /* Statistics about the allocation.  */
45e4b17023SJohn Marino static ggc_statistics *ggc_stats;
46e4b17023SJohn Marino 
47e4b17023SJohn Marino struct traversal_state;
48e4b17023SJohn Marino 
49e4b17023SJohn Marino static int ggc_htab_delete (void **, void *);
50e4b17023SJohn Marino static hashval_t saving_htab_hash (const void *);
51e4b17023SJohn Marino static int saving_htab_eq (const void *, const void *);
52e4b17023SJohn Marino static int call_count (void **, void *);
53e4b17023SJohn Marino static int call_alloc (void **, void *);
54e4b17023SJohn Marino static int compare_ptr_data (const void *, const void *);
55e4b17023SJohn Marino static void relocate_ptrs (void *, void *);
56e4b17023SJohn Marino static void write_pch_globals (const struct ggc_root_tab * const *tab,
57e4b17023SJohn Marino 			       struct traversal_state *state);
58e4b17023SJohn Marino 
59e4b17023SJohn Marino /* Maintain global roots that are preserved during GC.  */
60e4b17023SJohn Marino 
61e4b17023SJohn Marino /* Process a slot of an htab by deleting it if it has not been marked.  */
62e4b17023SJohn Marino 
63e4b17023SJohn Marino static int
ggc_htab_delete(void ** slot,void * info)64e4b17023SJohn Marino ggc_htab_delete (void **slot, void *info)
65e4b17023SJohn Marino {
66e4b17023SJohn Marino   const struct ggc_cache_tab *r = (const struct ggc_cache_tab *) info;
67e4b17023SJohn Marino 
68e4b17023SJohn Marino   if (! (*r->marked_p) (*slot))
69e4b17023SJohn Marino     htab_clear_slot (*r->base, slot);
70e4b17023SJohn Marino   else
71e4b17023SJohn Marino     (*r->cb) (*slot);
72e4b17023SJohn Marino 
73e4b17023SJohn Marino   return 1;
74e4b17023SJohn Marino }
75e4b17023SJohn Marino 
76e4b17023SJohn Marino 
77e4b17023SJohn Marino /* This extra vector of dynamically registered root_tab-s is used by
78e4b17023SJohn Marino    ggc_mark_roots and gives the ability to dynamically add new GGC root
79e4b17023SJohn Marino    tables, for instance from some plugins; this vector is on the heap
80e4b17023SJohn Marino    since it is used by GGC internally.  */
81e4b17023SJohn Marino typedef const struct ggc_root_tab *const_ggc_root_tab_t;
82e4b17023SJohn Marino DEF_VEC_P(const_ggc_root_tab_t);
83e4b17023SJohn Marino DEF_VEC_ALLOC_P(const_ggc_root_tab_t, heap);
VEC(const_ggc_root_tab_t,heap)84e4b17023SJohn Marino static VEC(const_ggc_root_tab_t, heap) *extra_root_vec;
85e4b17023SJohn Marino 
86e4b17023SJohn Marino /* Dynamically register a new GGC root table RT. This is useful for
87e4b17023SJohn Marino    plugins. */
88e4b17023SJohn Marino 
89e4b17023SJohn Marino void
90e4b17023SJohn Marino ggc_register_root_tab (const struct ggc_root_tab* rt)
91e4b17023SJohn Marino {
92e4b17023SJohn Marino   if (rt)
93e4b17023SJohn Marino     VEC_safe_push (const_ggc_root_tab_t, heap, extra_root_vec, rt);
94e4b17023SJohn Marino }
95e4b17023SJohn Marino 
96e4b17023SJohn Marino /* This extra vector of dynamically registered cache_tab-s is used by
97e4b17023SJohn Marino    ggc_mark_roots and gives the ability to dynamically add new GGC cache
98e4b17023SJohn Marino    tables, for instance from some plugins; this vector is on the heap
99e4b17023SJohn Marino    since it is used by GGC internally.  */
100e4b17023SJohn Marino typedef const struct ggc_cache_tab *const_ggc_cache_tab_t;
101e4b17023SJohn Marino DEF_VEC_P(const_ggc_cache_tab_t);
102e4b17023SJohn Marino DEF_VEC_ALLOC_P(const_ggc_cache_tab_t, heap);
VEC(const_ggc_cache_tab_t,heap)103e4b17023SJohn Marino static VEC(const_ggc_cache_tab_t, heap) *extra_cache_vec;
104e4b17023SJohn Marino 
105e4b17023SJohn Marino /* Dynamically register a new GGC cache table CT. This is useful for
106e4b17023SJohn Marino    plugins. */
107e4b17023SJohn Marino 
108e4b17023SJohn Marino void
109e4b17023SJohn Marino ggc_register_cache_tab (const struct ggc_cache_tab* ct)
110e4b17023SJohn Marino {
111e4b17023SJohn Marino   if (ct)
112e4b17023SJohn Marino     VEC_safe_push (const_ggc_cache_tab_t, heap, extra_cache_vec, ct);
113e4b17023SJohn Marino }
114e4b17023SJohn Marino 
115e4b17023SJohn Marino /* Scan a hash table that has objects which are to be deleted if they are not
116e4b17023SJohn Marino    already marked.  */
117e4b17023SJohn Marino 
118e4b17023SJohn Marino static void
ggc_scan_cache_tab(const_ggc_cache_tab_t ctp)119e4b17023SJohn Marino ggc_scan_cache_tab (const_ggc_cache_tab_t ctp)
120e4b17023SJohn Marino {
121e4b17023SJohn Marino   const struct ggc_cache_tab *cti;
122e4b17023SJohn Marino 
123e4b17023SJohn Marino   for (cti = ctp; cti->base != NULL; cti++)
124e4b17023SJohn Marino     if (*cti->base)
125e4b17023SJohn Marino       {
126e4b17023SJohn Marino         ggc_set_mark (*cti->base);
127e4b17023SJohn Marino         htab_traverse_noresize (*cti->base, ggc_htab_delete,
128e4b17023SJohn Marino                                 CONST_CAST (void *, (const void *)cti));
129e4b17023SJohn Marino         ggc_set_mark ((*cti->base)->entries);
130e4b17023SJohn Marino       }
131e4b17023SJohn Marino }
132e4b17023SJohn Marino 
133e4b17023SJohn Marino /* Mark all the roots in the table RT.  */
134e4b17023SJohn Marino 
135e4b17023SJohn Marino static void
ggc_mark_root_tab(const_ggc_root_tab_t rt)136e4b17023SJohn Marino ggc_mark_root_tab (const_ggc_root_tab_t rt)
137e4b17023SJohn Marino {
138e4b17023SJohn Marino   size_t i;
139e4b17023SJohn Marino 
140e4b17023SJohn Marino   for ( ; rt->base != NULL; rt++)
141e4b17023SJohn Marino     for (i = 0; i < rt->nelt; i++)
142e4b17023SJohn Marino       (*rt->cb) (*(void **) ((char *)rt->base + rt->stride * i));
143e4b17023SJohn Marino }
144e4b17023SJohn Marino 
145e4b17023SJohn Marino /* Iterate through all registered roots and mark each element.  */
146e4b17023SJohn Marino 
147e4b17023SJohn Marino void
ggc_mark_roots(void)148e4b17023SJohn Marino ggc_mark_roots (void)
149e4b17023SJohn Marino {
150e4b17023SJohn Marino   const struct ggc_root_tab *const *rt;
151e4b17023SJohn Marino   const_ggc_root_tab_t rtp, rti;
152e4b17023SJohn Marino   const struct ggc_cache_tab *const *ct;
153e4b17023SJohn Marino   const_ggc_cache_tab_t ctp;
154e4b17023SJohn Marino   size_t i;
155e4b17023SJohn Marino 
156e4b17023SJohn Marino   for (rt = gt_ggc_deletable_rtab; *rt; rt++)
157e4b17023SJohn Marino     for (rti = *rt; rti->base != NULL; rti++)
158e4b17023SJohn Marino       memset (rti->base, 0, rti->stride);
159e4b17023SJohn Marino 
160e4b17023SJohn Marino   for (rt = gt_ggc_rtab; *rt; rt++)
161e4b17023SJohn Marino     ggc_mark_root_tab (*rt);
162e4b17023SJohn Marino 
163e4b17023SJohn Marino   FOR_EACH_VEC_ELT (const_ggc_root_tab_t, extra_root_vec, i, rtp)
164e4b17023SJohn Marino     ggc_mark_root_tab (rtp);
165e4b17023SJohn Marino 
166e4b17023SJohn Marino   if (ggc_protect_identifiers)
167e4b17023SJohn Marino     ggc_mark_stringpool ();
168e4b17023SJohn Marino 
169e4b17023SJohn Marino   /* Now scan all hash tables that have objects which are to be deleted if
170e4b17023SJohn Marino      they are not already marked.  */
171e4b17023SJohn Marino   for (ct = gt_ggc_cache_rtab; *ct; ct++)
172e4b17023SJohn Marino     ggc_scan_cache_tab (*ct);
173e4b17023SJohn Marino 
174e4b17023SJohn Marino   FOR_EACH_VEC_ELT (const_ggc_cache_tab_t, extra_cache_vec, i, ctp)
175e4b17023SJohn Marino     ggc_scan_cache_tab (ctp);
176e4b17023SJohn Marino 
177e4b17023SJohn Marino   if (! ggc_protect_identifiers)
178e4b17023SJohn Marino     ggc_purge_stringpool ();
179e4b17023SJohn Marino 
180e4b17023SJohn Marino   /* Some plugins may call ggc_set_mark from here.  */
181e4b17023SJohn Marino   invoke_plugin_callbacks (PLUGIN_GGC_MARKING, NULL);
182e4b17023SJohn Marino }
183e4b17023SJohn Marino 
184e4b17023SJohn Marino /* Allocate a block of memory, then clear it.  */
185e4b17023SJohn Marino void *
ggc_internal_cleared_alloc_stat(size_t size MEM_STAT_DECL)186e4b17023SJohn Marino ggc_internal_cleared_alloc_stat (size_t size MEM_STAT_DECL)
187e4b17023SJohn Marino {
188e4b17023SJohn Marino   void *buf = ggc_internal_alloc_stat (size PASS_MEM_STAT);
189e4b17023SJohn Marino   memset (buf, 0, size);
190e4b17023SJohn Marino   return buf;
191e4b17023SJohn Marino }
192e4b17023SJohn Marino 
193e4b17023SJohn Marino /* Resize a block of memory, possibly re-allocating it.  */
194e4b17023SJohn Marino void *
ggc_realloc_stat(void * x,size_t size MEM_STAT_DECL)195e4b17023SJohn Marino ggc_realloc_stat (void *x, size_t size MEM_STAT_DECL)
196e4b17023SJohn Marino {
197e4b17023SJohn Marino   void *r;
198e4b17023SJohn Marino   size_t old_size;
199e4b17023SJohn Marino 
200e4b17023SJohn Marino   if (x == NULL)
201e4b17023SJohn Marino     return ggc_internal_alloc_stat (size PASS_MEM_STAT);
202e4b17023SJohn Marino 
203e4b17023SJohn Marino   old_size = ggc_get_size (x);
204e4b17023SJohn Marino 
205e4b17023SJohn Marino   if (size <= old_size)
206e4b17023SJohn Marino     {
207e4b17023SJohn Marino       /* Mark the unwanted memory as unaccessible.  We also need to make
208e4b17023SJohn Marino 	 the "new" size accessible, since ggc_get_size returns the size of
209e4b17023SJohn Marino 	 the pool, not the size of the individually allocated object, the
210e4b17023SJohn Marino 	 size which was previously made accessible.  Unfortunately, we
211e4b17023SJohn Marino 	 don't know that previously allocated size.  Without that
212e4b17023SJohn Marino 	 knowledge we have to lose some initialization-tracking for the
213e4b17023SJohn Marino 	 old parts of the object.  An alternative is to mark the whole
214e4b17023SJohn Marino 	 old_size as reachable, but that would lose tracking of writes
215e4b17023SJohn Marino 	 after the end of the object (by small offsets).  Discard the
216e4b17023SJohn Marino 	 handle to avoid handle leak.  */
217e4b17023SJohn Marino       VALGRIND_DISCARD (VALGRIND_MAKE_MEM_NOACCESS ((char *) x + size,
218e4b17023SJohn Marino 						    old_size - size));
219e4b17023SJohn Marino       VALGRIND_DISCARD (VALGRIND_MAKE_MEM_DEFINED (x, size));
220e4b17023SJohn Marino       return x;
221e4b17023SJohn Marino     }
222e4b17023SJohn Marino 
223e4b17023SJohn Marino   r = ggc_internal_alloc_stat (size PASS_MEM_STAT);
224e4b17023SJohn Marino 
225e4b17023SJohn Marino   /* Since ggc_get_size returns the size of the pool, not the size of the
226e4b17023SJohn Marino      individually allocated object, we'd access parts of the old object
227e4b17023SJohn Marino      that were marked invalid with the memcpy below.  We lose a bit of the
228e4b17023SJohn Marino      initialization-tracking since some of it may be uninitialized.  */
229e4b17023SJohn Marino   VALGRIND_DISCARD (VALGRIND_MAKE_MEM_DEFINED (x, old_size));
230e4b17023SJohn Marino 
231e4b17023SJohn Marino   memcpy (r, x, old_size);
232e4b17023SJohn Marino 
233e4b17023SJohn Marino   /* The old object is not supposed to be used anymore.  */
234e4b17023SJohn Marino   ggc_free (x);
235e4b17023SJohn Marino 
236e4b17023SJohn Marino   return r;
237e4b17023SJohn Marino }
238e4b17023SJohn Marino 
239e4b17023SJohn Marino void *
ggc_cleared_alloc_htab_ignore_args(size_t c ATTRIBUTE_UNUSED,size_t n ATTRIBUTE_UNUSED)240e4b17023SJohn Marino ggc_cleared_alloc_htab_ignore_args (size_t c ATTRIBUTE_UNUSED,
241e4b17023SJohn Marino 				    size_t n ATTRIBUTE_UNUSED)
242e4b17023SJohn Marino {
243e4b17023SJohn Marino   gcc_assert (c * n == sizeof (struct htab));
244e4b17023SJohn Marino   return ggc_alloc_cleared_htab ();
245e4b17023SJohn Marino }
246e4b17023SJohn Marino 
247e4b17023SJohn Marino /* TODO: once we actually use type information in GGC, create a new tag
248e4b17023SJohn Marino    gt_gcc_ptr_array and use it for pointer arrays.  */
249e4b17023SJohn Marino void *
ggc_cleared_alloc_ptr_array_two_args(size_t c,size_t n)250e4b17023SJohn Marino ggc_cleared_alloc_ptr_array_two_args (size_t c, size_t n)
251e4b17023SJohn Marino {
252e4b17023SJohn Marino   gcc_assert (sizeof (PTR *) == n);
253e4b17023SJohn Marino   return ggc_internal_cleared_vec_alloc (sizeof (PTR *), c);
254e4b17023SJohn Marino }
255e4b17023SJohn Marino 
256e4b17023SJohn Marino /* These are for splay_tree_new_ggc.  */
257e4b17023SJohn Marino void *
ggc_splay_alloc(enum gt_types_enum obj_type ATTRIBUTE_UNUSED,int sz,void * nl)258e4b17023SJohn Marino ggc_splay_alloc (enum gt_types_enum obj_type ATTRIBUTE_UNUSED, int sz,
259e4b17023SJohn Marino 		 void *nl)
260e4b17023SJohn Marino {
261e4b17023SJohn Marino   gcc_assert (!nl);
262e4b17023SJohn Marino   return ggc_internal_alloc (sz);
263e4b17023SJohn Marino }
264e4b17023SJohn Marino 
265e4b17023SJohn Marino void
ggc_splay_dont_free(void * x ATTRIBUTE_UNUSED,void * nl)266e4b17023SJohn Marino ggc_splay_dont_free (void * x ATTRIBUTE_UNUSED, void *nl)
267e4b17023SJohn Marino {
268e4b17023SJohn Marino   gcc_assert (!nl);
269e4b17023SJohn Marino }
270e4b17023SJohn Marino 
271e4b17023SJohn Marino /* Print statistics that are independent of the collector in use.  */
272e4b17023SJohn Marino #define SCALE(x) ((unsigned long) ((x) < 1024*10 \
273e4b17023SJohn Marino 		  ? (x) \
274e4b17023SJohn Marino 		  : ((x) < 1024*1024*10 \
275e4b17023SJohn Marino 		     ? (x) / 1024 \
276e4b17023SJohn Marino 		     : (x) / (1024*1024))))
277e4b17023SJohn Marino #define LABEL(x) ((x) < 1024*10 ? ' ' : ((x) < 1024*1024*10 ? 'k' : 'M'))
278e4b17023SJohn Marino 
279e4b17023SJohn Marino void
ggc_print_common_statistics(FILE * stream ATTRIBUTE_UNUSED,ggc_statistics * stats)280e4b17023SJohn Marino ggc_print_common_statistics (FILE *stream ATTRIBUTE_UNUSED,
281e4b17023SJohn Marino 			     ggc_statistics *stats)
282e4b17023SJohn Marino {
283e4b17023SJohn Marino   /* Set the pointer so that during collection we will actually gather
284e4b17023SJohn Marino      the statistics.  */
285e4b17023SJohn Marino   ggc_stats = stats;
286e4b17023SJohn Marino 
287e4b17023SJohn Marino   /* Then do one collection to fill in the statistics.  */
288e4b17023SJohn Marino   ggc_collect ();
289e4b17023SJohn Marino 
290e4b17023SJohn Marino   /* At present, we don't really gather any interesting statistics.  */
291e4b17023SJohn Marino 
292e4b17023SJohn Marino   /* Don't gather statistics any more.  */
293e4b17023SJohn Marino   ggc_stats = NULL;
294e4b17023SJohn Marino }
295e4b17023SJohn Marino 
296e4b17023SJohn Marino /* Functions for saving and restoring GCable memory to disk.  */
297e4b17023SJohn Marino 
298e4b17023SJohn Marino static htab_t saving_htab;
299e4b17023SJohn Marino 
300e4b17023SJohn Marino struct ptr_data
301e4b17023SJohn Marino {
302e4b17023SJohn Marino   void *obj;
303e4b17023SJohn Marino   void *note_ptr_cookie;
304e4b17023SJohn Marino   gt_note_pointers note_ptr_fn;
305e4b17023SJohn Marino   gt_handle_reorder reorder_fn;
306e4b17023SJohn Marino   size_t size;
307e4b17023SJohn Marino   void *new_addr;
308e4b17023SJohn Marino   enum gt_types_enum type;
309e4b17023SJohn Marino };
310e4b17023SJohn Marino 
311*5ce9237cSJohn Marino #define POINTER_HASH(x) (hashval_t)((intptr_t)x >> 3)
312e4b17023SJohn Marino 
313e4b17023SJohn Marino /* Register an object in the hash table.  */
314e4b17023SJohn Marino 
315e4b17023SJohn Marino int
gt_pch_note_object(void * obj,void * note_ptr_cookie,gt_note_pointers note_ptr_fn,enum gt_types_enum type)316e4b17023SJohn Marino gt_pch_note_object (void *obj, void *note_ptr_cookie,
317e4b17023SJohn Marino 		    gt_note_pointers note_ptr_fn,
318e4b17023SJohn Marino 		    enum gt_types_enum type)
319e4b17023SJohn Marino {
320e4b17023SJohn Marino   struct ptr_data **slot;
321e4b17023SJohn Marino 
322e4b17023SJohn Marino   if (obj == NULL || obj == (void *) 1)
323e4b17023SJohn Marino     return 0;
324e4b17023SJohn Marino 
325e4b17023SJohn Marino   slot = (struct ptr_data **)
326e4b17023SJohn Marino     htab_find_slot_with_hash (saving_htab, obj, POINTER_HASH (obj),
327e4b17023SJohn Marino 			      INSERT);
328e4b17023SJohn Marino   if (*slot != NULL)
329e4b17023SJohn Marino     {
330e4b17023SJohn Marino       gcc_assert ((*slot)->note_ptr_fn == note_ptr_fn
331e4b17023SJohn Marino 		  && (*slot)->note_ptr_cookie == note_ptr_cookie);
332e4b17023SJohn Marino       return 0;
333e4b17023SJohn Marino     }
334e4b17023SJohn Marino 
335e4b17023SJohn Marino   *slot = XCNEW (struct ptr_data);
336e4b17023SJohn Marino   (*slot)->obj = obj;
337e4b17023SJohn Marino   (*slot)->note_ptr_fn = note_ptr_fn;
338e4b17023SJohn Marino   (*slot)->note_ptr_cookie = note_ptr_cookie;
339e4b17023SJohn Marino   if (note_ptr_fn == gt_pch_p_S)
340e4b17023SJohn Marino     (*slot)->size = strlen ((const char *)obj) + 1;
341e4b17023SJohn Marino   else
342e4b17023SJohn Marino     (*slot)->size = ggc_get_size (obj);
343e4b17023SJohn Marino   (*slot)->type = type;
344e4b17023SJohn Marino   return 1;
345e4b17023SJohn Marino }
346e4b17023SJohn Marino 
347e4b17023SJohn Marino /* Register an object in the hash table.  */
348e4b17023SJohn Marino 
349e4b17023SJohn Marino void
gt_pch_note_reorder(void * obj,void * note_ptr_cookie,gt_handle_reorder reorder_fn)350e4b17023SJohn Marino gt_pch_note_reorder (void *obj, void *note_ptr_cookie,
351e4b17023SJohn Marino 		     gt_handle_reorder reorder_fn)
352e4b17023SJohn Marino {
353e4b17023SJohn Marino   struct ptr_data *data;
354e4b17023SJohn Marino 
355e4b17023SJohn Marino   if (obj == NULL || obj == (void *) 1)
356e4b17023SJohn Marino     return;
357e4b17023SJohn Marino 
358e4b17023SJohn Marino   data = (struct ptr_data *)
359e4b17023SJohn Marino     htab_find_with_hash (saving_htab, obj, POINTER_HASH (obj));
360e4b17023SJohn Marino   gcc_assert (data && data->note_ptr_cookie == note_ptr_cookie);
361e4b17023SJohn Marino 
362e4b17023SJohn Marino   data->reorder_fn = reorder_fn;
363e4b17023SJohn Marino }
364e4b17023SJohn Marino 
365e4b17023SJohn Marino /* Hash and equality functions for saving_htab, callbacks for htab_create.  */
366e4b17023SJohn Marino 
367e4b17023SJohn Marino static hashval_t
saving_htab_hash(const void * p)368e4b17023SJohn Marino saving_htab_hash (const void *p)
369e4b17023SJohn Marino {
370e4b17023SJohn Marino   return POINTER_HASH (((const struct ptr_data *)p)->obj);
371e4b17023SJohn Marino }
372e4b17023SJohn Marino 
373e4b17023SJohn Marino static int
saving_htab_eq(const void * p1,const void * p2)374e4b17023SJohn Marino saving_htab_eq (const void *p1, const void *p2)
375e4b17023SJohn Marino {
376e4b17023SJohn Marino   return ((const struct ptr_data *)p1)->obj == p2;
377e4b17023SJohn Marino }
378e4b17023SJohn Marino 
379e4b17023SJohn Marino /* Handy state for the traversal functions.  */
380e4b17023SJohn Marino 
381e4b17023SJohn Marino struct traversal_state
382e4b17023SJohn Marino {
383e4b17023SJohn Marino   FILE *f;
384e4b17023SJohn Marino   struct ggc_pch_data *d;
385e4b17023SJohn Marino   size_t count;
386e4b17023SJohn Marino   struct ptr_data **ptrs;
387e4b17023SJohn Marino   size_t ptrs_i;
388e4b17023SJohn Marino };
389e4b17023SJohn Marino 
390e4b17023SJohn Marino /* Callbacks for htab_traverse.  */
391e4b17023SJohn Marino 
392e4b17023SJohn Marino static int
call_count(void ** slot,void * state_p)393e4b17023SJohn Marino call_count (void **slot, void *state_p)
394e4b17023SJohn Marino {
395e4b17023SJohn Marino   struct ptr_data *d = (struct ptr_data *)*slot;
396e4b17023SJohn Marino   struct traversal_state *state = (struct traversal_state *)state_p;
397e4b17023SJohn Marino 
398e4b17023SJohn Marino   ggc_pch_count_object (state->d, d->obj, d->size,
399e4b17023SJohn Marino 			d->note_ptr_fn == gt_pch_p_S,
400e4b17023SJohn Marino 			d->type);
401e4b17023SJohn Marino   state->count++;
402e4b17023SJohn Marino   return 1;
403e4b17023SJohn Marino }
404e4b17023SJohn Marino 
405e4b17023SJohn Marino static int
call_alloc(void ** slot,void * state_p)406e4b17023SJohn Marino call_alloc (void **slot, void *state_p)
407e4b17023SJohn Marino {
408e4b17023SJohn Marino   struct ptr_data *d = (struct ptr_data *)*slot;
409e4b17023SJohn Marino   struct traversal_state *state = (struct traversal_state *)state_p;
410e4b17023SJohn Marino 
411e4b17023SJohn Marino   d->new_addr = ggc_pch_alloc_object (state->d, d->obj, d->size,
412e4b17023SJohn Marino 				      d->note_ptr_fn == gt_pch_p_S,
413e4b17023SJohn Marino 				      d->type);
414e4b17023SJohn Marino   state->ptrs[state->ptrs_i++] = d;
415e4b17023SJohn Marino   return 1;
416e4b17023SJohn Marino }
417e4b17023SJohn Marino 
418e4b17023SJohn Marino /* Callback for qsort.  */
419e4b17023SJohn Marino 
420e4b17023SJohn Marino static int
compare_ptr_data(const void * p1_p,const void * p2_p)421e4b17023SJohn Marino compare_ptr_data (const void *p1_p, const void *p2_p)
422e4b17023SJohn Marino {
423e4b17023SJohn Marino   const struct ptr_data *const p1 = *(const struct ptr_data *const *)p1_p;
424e4b17023SJohn Marino   const struct ptr_data *const p2 = *(const struct ptr_data *const *)p2_p;
425e4b17023SJohn Marino   return (((size_t)p1->new_addr > (size_t)p2->new_addr)
426e4b17023SJohn Marino 	  - ((size_t)p1->new_addr < (size_t)p2->new_addr));
427e4b17023SJohn Marino }
428e4b17023SJohn Marino 
429e4b17023SJohn Marino /* Callbacks for note_ptr_fn.  */
430e4b17023SJohn Marino 
431e4b17023SJohn Marino static void
relocate_ptrs(void * ptr_p,void * state_p)432e4b17023SJohn Marino relocate_ptrs (void *ptr_p, void *state_p)
433e4b17023SJohn Marino {
434e4b17023SJohn Marino   void **ptr = (void **)ptr_p;
435e4b17023SJohn Marino   struct traversal_state *state ATTRIBUTE_UNUSED
436e4b17023SJohn Marino     = (struct traversal_state *)state_p;
437e4b17023SJohn Marino   struct ptr_data *result;
438e4b17023SJohn Marino 
439e4b17023SJohn Marino   if (*ptr == NULL || *ptr == (void *)1)
440e4b17023SJohn Marino     return;
441e4b17023SJohn Marino 
442e4b17023SJohn Marino   result = (struct ptr_data *)
443e4b17023SJohn Marino     htab_find_with_hash (saving_htab, *ptr, POINTER_HASH (*ptr));
444e4b17023SJohn Marino   gcc_assert (result);
445e4b17023SJohn Marino   *ptr = result->new_addr;
446e4b17023SJohn Marino }
447e4b17023SJohn Marino 
448e4b17023SJohn Marino /* Write out, after relocation, the pointers in TAB.  */
449e4b17023SJohn Marino static void
write_pch_globals(const struct ggc_root_tab * const * tab,struct traversal_state * state)450e4b17023SJohn Marino write_pch_globals (const struct ggc_root_tab * const *tab,
451e4b17023SJohn Marino 		   struct traversal_state *state)
452e4b17023SJohn Marino {
453e4b17023SJohn Marino   const struct ggc_root_tab *const *rt;
454e4b17023SJohn Marino   const struct ggc_root_tab *rti;
455e4b17023SJohn Marino   size_t i;
456e4b17023SJohn Marino 
457e4b17023SJohn Marino   for (rt = tab; *rt; rt++)
458e4b17023SJohn Marino     for (rti = *rt; rti->base != NULL; rti++)
459e4b17023SJohn Marino       for (i = 0; i < rti->nelt; i++)
460e4b17023SJohn Marino 	{
461e4b17023SJohn Marino 	  void *ptr = *(void **)((char *)rti->base + rti->stride * i);
462e4b17023SJohn Marino 	  struct ptr_data *new_ptr;
463e4b17023SJohn Marino 	  if (ptr == NULL || ptr == (void *)1)
464e4b17023SJohn Marino 	    {
465e4b17023SJohn Marino 	      if (fwrite (&ptr, sizeof (void *), 1, state->f)
466e4b17023SJohn Marino 		  != 1)
467e4b17023SJohn Marino 		fatal_error ("can%'t write PCH file: %m");
468e4b17023SJohn Marino 	    }
469e4b17023SJohn Marino 	  else
470e4b17023SJohn Marino 	    {
471e4b17023SJohn Marino 	      new_ptr = (struct ptr_data *)
472e4b17023SJohn Marino 		htab_find_with_hash (saving_htab, ptr, POINTER_HASH (ptr));
473e4b17023SJohn Marino 	      if (fwrite (&new_ptr->new_addr, sizeof (void *), 1, state->f)
474e4b17023SJohn Marino 		  != 1)
475e4b17023SJohn Marino 		fatal_error ("can%'t write PCH file: %m");
476e4b17023SJohn Marino 	    }
477e4b17023SJohn Marino 	}
478e4b17023SJohn Marino }
479e4b17023SJohn Marino 
480e4b17023SJohn Marino /* Hold the information we need to mmap the file back in.  */
481e4b17023SJohn Marino 
482e4b17023SJohn Marino struct mmap_info
483e4b17023SJohn Marino {
484e4b17023SJohn Marino   size_t offset;
485e4b17023SJohn Marino   size_t size;
486e4b17023SJohn Marino   void *preferred_base;
487e4b17023SJohn Marino };
488e4b17023SJohn Marino 
489e4b17023SJohn Marino /* Write out the state of the compiler to F.  */
490e4b17023SJohn Marino 
491e4b17023SJohn Marino void
gt_pch_save(FILE * f)492e4b17023SJohn Marino gt_pch_save (FILE *f)
493e4b17023SJohn Marino {
494e4b17023SJohn Marino   const struct ggc_root_tab *const *rt;
495e4b17023SJohn Marino   const struct ggc_root_tab *rti;
496e4b17023SJohn Marino   size_t i;
497e4b17023SJohn Marino   struct traversal_state state;
498e4b17023SJohn Marino   char *this_object = NULL;
499e4b17023SJohn Marino   size_t this_object_size = 0;
500e4b17023SJohn Marino   struct mmap_info mmi;
501e4b17023SJohn Marino   const size_t mmap_offset_alignment = host_hooks.gt_pch_alloc_granularity();
502e4b17023SJohn Marino 
503e4b17023SJohn Marino   gt_pch_save_stringpool ();
504e4b17023SJohn Marino 
505e4b17023SJohn Marino   timevar_push (TV_PCH_PTR_REALLOC);
506e4b17023SJohn Marino   saving_htab = htab_create (50000, saving_htab_hash, saving_htab_eq, free);
507e4b17023SJohn Marino 
508e4b17023SJohn Marino   for (rt = gt_ggc_rtab; *rt; rt++)
509e4b17023SJohn Marino     for (rti = *rt; rti->base != NULL; rti++)
510e4b17023SJohn Marino       for (i = 0; i < rti->nelt; i++)
511e4b17023SJohn Marino 	(*rti->pchw)(*(void **)((char *)rti->base + rti->stride * i));
512e4b17023SJohn Marino 
513e4b17023SJohn Marino   for (rt = gt_pch_cache_rtab; *rt; rt++)
514e4b17023SJohn Marino     for (rti = *rt; rti->base != NULL; rti++)
515e4b17023SJohn Marino       for (i = 0; i < rti->nelt; i++)
516e4b17023SJohn Marino 	(*rti->pchw)(*(void **)((char *)rti->base + rti->stride * i));
517e4b17023SJohn Marino 
518e4b17023SJohn Marino   /* Prepare the objects for writing, determine addresses and such.  */
519e4b17023SJohn Marino   state.f = f;
520e4b17023SJohn Marino   state.d = init_ggc_pch ();
521e4b17023SJohn Marino   state.count = 0;
522e4b17023SJohn Marino   htab_traverse (saving_htab, call_count, &state);
523e4b17023SJohn Marino 
524e4b17023SJohn Marino   mmi.size = ggc_pch_total_size (state.d);
525e4b17023SJohn Marino 
526e4b17023SJohn Marino   /* Try to arrange things so that no relocation is necessary, but
527e4b17023SJohn Marino      don't try very hard.  On most platforms, this will always work,
528e4b17023SJohn Marino      and on the rest it's a lot of work to do better.
529e4b17023SJohn Marino      (The extra work goes in HOST_HOOKS_GT_PCH_GET_ADDRESS and
530e4b17023SJohn Marino      HOST_HOOKS_GT_PCH_USE_ADDRESS.)  */
531e4b17023SJohn Marino   mmi.preferred_base = host_hooks.gt_pch_get_address (mmi.size, fileno (f));
532e4b17023SJohn Marino 
533e4b17023SJohn Marino   ggc_pch_this_base (state.d, mmi.preferred_base);
534e4b17023SJohn Marino 
535e4b17023SJohn Marino   state.ptrs = XNEWVEC (struct ptr_data *, state.count);
536e4b17023SJohn Marino   state.ptrs_i = 0;
537e4b17023SJohn Marino 
538e4b17023SJohn Marino   htab_traverse (saving_htab, call_alloc, &state);
539e4b17023SJohn Marino   timevar_pop (TV_PCH_PTR_REALLOC);
540e4b17023SJohn Marino 
541e4b17023SJohn Marino   timevar_push (TV_PCH_PTR_SORT);
542e4b17023SJohn Marino   qsort (state.ptrs, state.count, sizeof (*state.ptrs), compare_ptr_data);
543e4b17023SJohn Marino   timevar_pop (TV_PCH_PTR_SORT);
544e4b17023SJohn Marino 
545e4b17023SJohn Marino   /* Write out all the scalar variables.  */
546e4b17023SJohn Marino   for (rt = gt_pch_scalar_rtab; *rt; rt++)
547e4b17023SJohn Marino     for (rti = *rt; rti->base != NULL; rti++)
548e4b17023SJohn Marino       if (fwrite (rti->base, rti->stride, 1, f) != 1)
549e4b17023SJohn Marino 	fatal_error ("can%'t write PCH file: %m");
550e4b17023SJohn Marino 
551e4b17023SJohn Marino   /* Write out all the global pointers, after translation.  */
552e4b17023SJohn Marino   write_pch_globals (gt_ggc_rtab, &state);
553e4b17023SJohn Marino   write_pch_globals (gt_pch_cache_rtab, &state);
554e4b17023SJohn Marino 
555e4b17023SJohn Marino   /* Pad the PCH file so that the mmapped area starts on an allocation
556e4b17023SJohn Marino      granularity (usually page) boundary.  */
557e4b17023SJohn Marino   {
558e4b17023SJohn Marino     long o;
559e4b17023SJohn Marino     o = ftell (state.f) + sizeof (mmi);
560e4b17023SJohn Marino     if (o == -1)
561e4b17023SJohn Marino       fatal_error ("can%'t get position in PCH file: %m");
562e4b17023SJohn Marino     mmi.offset = mmap_offset_alignment - o % mmap_offset_alignment;
563e4b17023SJohn Marino     if (mmi.offset == mmap_offset_alignment)
564e4b17023SJohn Marino       mmi.offset = 0;
565e4b17023SJohn Marino     mmi.offset += o;
566e4b17023SJohn Marino   }
567e4b17023SJohn Marino   if (fwrite (&mmi, sizeof (mmi), 1, state.f) != 1)
568e4b17023SJohn Marino     fatal_error ("can%'t write PCH file: %m");
569e4b17023SJohn Marino   if (mmi.offset != 0
570e4b17023SJohn Marino       && fseek (state.f, mmi.offset, SEEK_SET) != 0)
571e4b17023SJohn Marino     fatal_error ("can%'t write padding to PCH file: %m");
572e4b17023SJohn Marino 
573e4b17023SJohn Marino   ggc_pch_prepare_write (state.d, state.f);
574e4b17023SJohn Marino 
575e4b17023SJohn Marino   /* Actually write out the objects.  */
576e4b17023SJohn Marino   for (i = 0; i < state.count; i++)
577e4b17023SJohn Marino     {
578e4b17023SJohn Marino       if (this_object_size < state.ptrs[i]->size)
579e4b17023SJohn Marino 	{
580e4b17023SJohn Marino 	  this_object_size = state.ptrs[i]->size;
581e4b17023SJohn Marino 	  this_object = XRESIZEVAR (char, this_object, this_object_size);
582e4b17023SJohn Marino 	}
583e4b17023SJohn Marino       memcpy (this_object, state.ptrs[i]->obj, state.ptrs[i]->size);
584e4b17023SJohn Marino       if (state.ptrs[i]->reorder_fn != NULL)
585e4b17023SJohn Marino 	state.ptrs[i]->reorder_fn (state.ptrs[i]->obj,
586e4b17023SJohn Marino 				   state.ptrs[i]->note_ptr_cookie,
587e4b17023SJohn Marino 				   relocate_ptrs, &state);
588e4b17023SJohn Marino       state.ptrs[i]->note_ptr_fn (state.ptrs[i]->obj,
589e4b17023SJohn Marino 				  state.ptrs[i]->note_ptr_cookie,
590e4b17023SJohn Marino 				  relocate_ptrs, &state);
591e4b17023SJohn Marino       ggc_pch_write_object (state.d, state.f, state.ptrs[i]->obj,
592e4b17023SJohn Marino 			    state.ptrs[i]->new_addr, state.ptrs[i]->size,
593e4b17023SJohn Marino 			    state.ptrs[i]->note_ptr_fn == gt_pch_p_S);
594e4b17023SJohn Marino       if (state.ptrs[i]->note_ptr_fn != gt_pch_p_S)
595e4b17023SJohn Marino 	memcpy (state.ptrs[i]->obj, this_object, state.ptrs[i]->size);
596e4b17023SJohn Marino     }
597e4b17023SJohn Marino   ggc_pch_finish (state.d, state.f);
598e4b17023SJohn Marino   gt_pch_fixup_stringpool ();
599e4b17023SJohn Marino 
600e4b17023SJohn Marino   free (state.ptrs);
601e4b17023SJohn Marino   htab_delete (saving_htab);
602e4b17023SJohn Marino }
603e4b17023SJohn Marino 
604e4b17023SJohn Marino /* Read the state of the compiler back in from F.  */
605e4b17023SJohn Marino 
606e4b17023SJohn Marino void
gt_pch_restore(FILE * f)607e4b17023SJohn Marino gt_pch_restore (FILE *f)
608e4b17023SJohn Marino {
609e4b17023SJohn Marino   const struct ggc_root_tab *const *rt;
610e4b17023SJohn Marino   const struct ggc_root_tab *rti;
611e4b17023SJohn Marino   size_t i;
612e4b17023SJohn Marino   struct mmap_info mmi;
613e4b17023SJohn Marino   int result;
614e4b17023SJohn Marino 
615e4b17023SJohn Marino   /* Delete any deletable objects.  This makes ggc_pch_read much
616e4b17023SJohn Marino      faster, as it can be sure that no GCable objects remain other
617e4b17023SJohn Marino      than the ones just read in.  */
618e4b17023SJohn Marino   for (rt = gt_ggc_deletable_rtab; *rt; rt++)
619e4b17023SJohn Marino     for (rti = *rt; rti->base != NULL; rti++)
620e4b17023SJohn Marino       memset (rti->base, 0, rti->stride);
621e4b17023SJohn Marino 
622e4b17023SJohn Marino   /* Read in all the scalar variables.  */
623e4b17023SJohn Marino   for (rt = gt_pch_scalar_rtab; *rt; rt++)
624e4b17023SJohn Marino     for (rti = *rt; rti->base != NULL; rti++)
625e4b17023SJohn Marino       if (fread (rti->base, rti->stride, 1, f) != 1)
626e4b17023SJohn Marino 	fatal_error ("can%'t read PCH file: %m");
627e4b17023SJohn Marino 
628e4b17023SJohn Marino   /* Read in all the global pointers, in 6 easy loops.  */
629e4b17023SJohn Marino   for (rt = gt_ggc_rtab; *rt; rt++)
630e4b17023SJohn Marino     for (rti = *rt; rti->base != NULL; rti++)
631e4b17023SJohn Marino       for (i = 0; i < rti->nelt; i++)
632e4b17023SJohn Marino 	if (fread ((char *)rti->base + rti->stride * i,
633e4b17023SJohn Marino 		   sizeof (void *), 1, f) != 1)
634e4b17023SJohn Marino 	  fatal_error ("can%'t read PCH file: %m");
635e4b17023SJohn Marino 
636e4b17023SJohn Marino   for (rt = gt_pch_cache_rtab; *rt; rt++)
637e4b17023SJohn Marino     for (rti = *rt; rti->base != NULL; rti++)
638e4b17023SJohn Marino       for (i = 0; i < rti->nelt; i++)
639e4b17023SJohn Marino 	if (fread ((char *)rti->base + rti->stride * i,
640e4b17023SJohn Marino 		   sizeof (void *), 1, f) != 1)
641e4b17023SJohn Marino 	  fatal_error ("can%'t read PCH file: %m");
642e4b17023SJohn Marino 
643e4b17023SJohn Marino   if (fread (&mmi, sizeof (mmi), 1, f) != 1)
644e4b17023SJohn Marino     fatal_error ("can%'t read PCH file: %m");
645e4b17023SJohn Marino 
646e4b17023SJohn Marino   result = host_hooks.gt_pch_use_address (mmi.preferred_base, mmi.size,
647e4b17023SJohn Marino 					  fileno (f), mmi.offset);
648e4b17023SJohn Marino   if (result < 0)
649e4b17023SJohn Marino     fatal_error ("had to relocate PCH");
650e4b17023SJohn Marino   if (result == 0)
651e4b17023SJohn Marino     {
652e4b17023SJohn Marino       if (fseek (f, mmi.offset, SEEK_SET) != 0
653e4b17023SJohn Marino 	  || fread (mmi.preferred_base, mmi.size, 1, f) != 1)
654e4b17023SJohn Marino 	fatal_error ("can%'t read PCH file: %m");
655e4b17023SJohn Marino     }
656e4b17023SJohn Marino   else if (fseek (f, mmi.offset + mmi.size, SEEK_SET) != 0)
657e4b17023SJohn Marino     fatal_error ("can%'t read PCH file: %m");
658e4b17023SJohn Marino 
659e4b17023SJohn Marino   ggc_pch_read (f, mmi.preferred_base);
660e4b17023SJohn Marino 
661e4b17023SJohn Marino   gt_pch_restore_stringpool ();
662e4b17023SJohn Marino }
663e4b17023SJohn Marino 
664e4b17023SJohn Marino /* Default version of HOST_HOOKS_GT_PCH_GET_ADDRESS when mmap is not present.
665e4b17023SJohn Marino    Select no address whatsoever, and let gt_pch_save choose what it will with
666e4b17023SJohn Marino    malloc, presumably.  */
667e4b17023SJohn Marino 
668e4b17023SJohn Marino void *
default_gt_pch_get_address(size_t size ATTRIBUTE_UNUSED,int fd ATTRIBUTE_UNUSED)669e4b17023SJohn Marino default_gt_pch_get_address (size_t size ATTRIBUTE_UNUSED,
670e4b17023SJohn Marino 			    int fd ATTRIBUTE_UNUSED)
671e4b17023SJohn Marino {
672e4b17023SJohn Marino   return NULL;
673e4b17023SJohn Marino }
674e4b17023SJohn Marino 
675e4b17023SJohn Marino /* Default version of HOST_HOOKS_GT_PCH_USE_ADDRESS when mmap is not present.
676e4b17023SJohn Marino    Allocate SIZE bytes with malloc.  Return 0 if the address we got is the
677e4b17023SJohn Marino    same as base, indicating that the memory has been allocated but needs to
678e4b17023SJohn Marino    be read in from the file.  Return -1 if the address differs, to relocation
679e4b17023SJohn Marino    of the PCH file would be required.  */
680e4b17023SJohn Marino 
681e4b17023SJohn Marino int
default_gt_pch_use_address(void * base,size_t size,int fd ATTRIBUTE_UNUSED,size_t offset ATTRIBUTE_UNUSED)682e4b17023SJohn Marino default_gt_pch_use_address (void *base, size_t size, int fd ATTRIBUTE_UNUSED,
683e4b17023SJohn Marino 			    size_t offset ATTRIBUTE_UNUSED)
684e4b17023SJohn Marino {
685e4b17023SJohn Marino   void *addr = xmalloc (size);
686e4b17023SJohn Marino   return (addr == base) - 1;
687e4b17023SJohn Marino }
688e4b17023SJohn Marino 
689e4b17023SJohn Marino /* Default version of HOST_HOOKS_GT_PCH_GET_ADDRESS.   Return the
690e4b17023SJohn Marino    alignment required for allocating virtual memory. Usually this is the
691e4b17023SJohn Marino    same as pagesize.  */
692e4b17023SJohn Marino 
693e4b17023SJohn Marino size_t
default_gt_pch_alloc_granularity(void)694e4b17023SJohn Marino default_gt_pch_alloc_granularity (void)
695e4b17023SJohn Marino {
696e4b17023SJohn Marino   return getpagesize();
697e4b17023SJohn Marino }
698e4b17023SJohn Marino 
699e4b17023SJohn Marino #if HAVE_MMAP_FILE
700e4b17023SJohn Marino /* Default version of HOST_HOOKS_GT_PCH_GET_ADDRESS when mmap is present.
701e4b17023SJohn Marino    We temporarily allocate SIZE bytes, and let the kernel place the data
702e4b17023SJohn Marino    wherever it will.  If it worked, that's our spot, if not we're likely
703e4b17023SJohn Marino    to be in trouble.  */
704e4b17023SJohn Marino 
705e4b17023SJohn Marino void *
mmap_gt_pch_get_address(size_t size,int fd)706e4b17023SJohn Marino mmap_gt_pch_get_address (size_t size, int fd)
707e4b17023SJohn Marino {
708e4b17023SJohn Marino   void *ret;
709e4b17023SJohn Marino 
710e4b17023SJohn Marino   ret = mmap (NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
711e4b17023SJohn Marino   if (ret == (void *) MAP_FAILED)
712e4b17023SJohn Marino     ret = NULL;
713e4b17023SJohn Marino   else
714e4b17023SJohn Marino     munmap ((caddr_t) ret, size);
715e4b17023SJohn Marino 
716e4b17023SJohn Marino   return ret;
717e4b17023SJohn Marino }
718e4b17023SJohn Marino 
719e4b17023SJohn Marino /* Default version of HOST_HOOKS_GT_PCH_USE_ADDRESS when mmap is present.
720e4b17023SJohn Marino    Map SIZE bytes of FD+OFFSET at BASE.  Return 1 if we succeeded at
721e4b17023SJohn Marino    mapping the data at BASE, -1 if we couldn't.
722e4b17023SJohn Marino 
723e4b17023SJohn Marino    This version assumes that the kernel honors the START operand of mmap
724e4b17023SJohn Marino    even without MAP_FIXED if START through START+SIZE are not currently
725e4b17023SJohn Marino    mapped with something.  */
726e4b17023SJohn Marino 
727e4b17023SJohn Marino int
mmap_gt_pch_use_address(void * base,size_t size,int fd,size_t offset)728e4b17023SJohn Marino mmap_gt_pch_use_address (void *base, size_t size, int fd, size_t offset)
729e4b17023SJohn Marino {
730e4b17023SJohn Marino   void *addr;
731e4b17023SJohn Marino 
732e4b17023SJohn Marino   /* We're called with size == 0 if we're not planning to load a PCH
733e4b17023SJohn Marino      file at all.  This allows the hook to free any static space that
734e4b17023SJohn Marino      we might have allocated at link time.  */
735e4b17023SJohn Marino   if (size == 0)
736e4b17023SJohn Marino     return -1;
737e4b17023SJohn Marino 
738e4b17023SJohn Marino   addr = mmap ((caddr_t) base, size, PROT_READ | PROT_WRITE, MAP_PRIVATE,
739e4b17023SJohn Marino 	       fd, offset);
740e4b17023SJohn Marino 
741e4b17023SJohn Marino   return addr == base ? 1 : -1;
742e4b17023SJohn Marino }
743e4b17023SJohn Marino #endif /* HAVE_MMAP_FILE */
744e4b17023SJohn Marino 
745e4b17023SJohn Marino #if !defined ENABLE_GC_CHECKING && !defined ENABLE_GC_ALWAYS_COLLECT
746e4b17023SJohn Marino 
747e4b17023SJohn Marino /* Modify the bound based on rlimits.  */
748e4b17023SJohn Marino static double
ggc_rlimit_bound(double limit)749e4b17023SJohn Marino ggc_rlimit_bound (double limit)
750e4b17023SJohn Marino {
751e4b17023SJohn Marino #if defined(HAVE_GETRLIMIT)
752e4b17023SJohn Marino   struct rlimit rlim;
753e4b17023SJohn Marino # if defined (RLIMIT_AS)
754e4b17023SJohn Marino   /* RLIMIT_AS is what POSIX says is the limit on mmap.  Presumably
755e4b17023SJohn Marino      any OS which has RLIMIT_AS also has a working mmap that GCC will use.  */
756e4b17023SJohn Marino   if (getrlimit (RLIMIT_AS, &rlim) == 0
757e4b17023SJohn Marino       && rlim.rlim_cur != (rlim_t) RLIM_INFINITY
758e4b17023SJohn Marino       && rlim.rlim_cur < limit)
759e4b17023SJohn Marino     limit = rlim.rlim_cur;
760e4b17023SJohn Marino # elif defined (RLIMIT_DATA)
761e4b17023SJohn Marino   /* ... but some older OSs bound mmap based on RLIMIT_DATA, or we
762e4b17023SJohn Marino      might be on an OS that has a broken mmap.  (Others don't bound
763e4b17023SJohn Marino      mmap at all, apparently.)  */
764e4b17023SJohn Marino   if (getrlimit (RLIMIT_DATA, &rlim) == 0
765e4b17023SJohn Marino       && rlim.rlim_cur != (rlim_t) RLIM_INFINITY
766e4b17023SJohn Marino       && rlim.rlim_cur < limit
767e4b17023SJohn Marino       /* Darwin has this horribly bogus default setting of
768e4b17023SJohn Marino 	 RLIMIT_DATA, to 6144Kb.  No-one notices because RLIMIT_DATA
769e4b17023SJohn Marino 	 appears to be ignored.  Ignore such silliness.  If a limit
770e4b17023SJohn Marino 	 this small was actually effective for mmap, GCC wouldn't even
771e4b17023SJohn Marino 	 start up.  */
772e4b17023SJohn Marino       && rlim.rlim_cur >= 8 * 1024 * 1024)
773e4b17023SJohn Marino     limit = rlim.rlim_cur;
774e4b17023SJohn Marino # endif /* RLIMIT_AS or RLIMIT_DATA */
775e4b17023SJohn Marino #endif /* HAVE_GETRLIMIT */
776e4b17023SJohn Marino 
777e4b17023SJohn Marino   return limit;
778e4b17023SJohn Marino }
779e4b17023SJohn Marino 
780e4b17023SJohn Marino /* Heuristic to set a default for GGC_MIN_EXPAND.  */
781e4b17023SJohn Marino static int
ggc_min_expand_heuristic(void)782e4b17023SJohn Marino ggc_min_expand_heuristic (void)
783e4b17023SJohn Marino {
784e4b17023SJohn Marino   double min_expand = physmem_total();
785e4b17023SJohn Marino 
786e4b17023SJohn Marino   /* Adjust for rlimits.  */
787e4b17023SJohn Marino   min_expand = ggc_rlimit_bound (min_expand);
788e4b17023SJohn Marino 
789e4b17023SJohn Marino   /* The heuristic is a percentage equal to 30% + 70%*(RAM/1GB), yielding
790e4b17023SJohn Marino      a lower bound of 30% and an upper bound of 100% (when RAM >= 1GB).  */
791e4b17023SJohn Marino   min_expand /= 1024*1024*1024;
792e4b17023SJohn Marino   min_expand *= 70;
793e4b17023SJohn Marino   min_expand = MIN (min_expand, 70);
794e4b17023SJohn Marino   min_expand += 30;
795e4b17023SJohn Marino 
796e4b17023SJohn Marino   return min_expand;
797e4b17023SJohn Marino }
798e4b17023SJohn Marino 
799e4b17023SJohn Marino /* Heuristic to set a default for GGC_MIN_HEAPSIZE.  */
800e4b17023SJohn Marino static int
ggc_min_heapsize_heuristic(void)801e4b17023SJohn Marino ggc_min_heapsize_heuristic (void)
802e4b17023SJohn Marino {
803e4b17023SJohn Marino   double phys_kbytes = physmem_total();
804e4b17023SJohn Marino   double limit_kbytes = ggc_rlimit_bound (phys_kbytes * 2);
805e4b17023SJohn Marino 
806e4b17023SJohn Marino   phys_kbytes /= 1024; /* Convert to Kbytes.  */
807e4b17023SJohn Marino   limit_kbytes /= 1024;
808e4b17023SJohn Marino 
809e4b17023SJohn Marino   /* The heuristic is RAM/8, with a lower bound of 4M and an upper
810e4b17023SJohn Marino      bound of 128M (when RAM >= 1GB).  */
811e4b17023SJohn Marino   phys_kbytes /= 8;
812e4b17023SJohn Marino 
813e4b17023SJohn Marino #if defined(HAVE_GETRLIMIT) && defined (RLIMIT_RSS)
814e4b17023SJohn Marino   /* Try not to overrun the RSS limit while doing garbage collection.
815e4b17023SJohn Marino      The RSS limit is only advisory, so no margin is subtracted.  */
816e4b17023SJohn Marino  {
817e4b17023SJohn Marino    struct rlimit rlim;
818e4b17023SJohn Marino    if (getrlimit (RLIMIT_RSS, &rlim) == 0
819e4b17023SJohn Marino        && rlim.rlim_cur != (rlim_t) RLIM_INFINITY)
820e4b17023SJohn Marino      phys_kbytes = MIN (phys_kbytes, rlim.rlim_cur / 1024);
821e4b17023SJohn Marino  }
822e4b17023SJohn Marino # endif
823e4b17023SJohn Marino 
824e4b17023SJohn Marino   /* Don't blindly run over our data limit; do GC at least when the
825e4b17023SJohn Marino      *next* GC would be within 20Mb of the limit or within a quarter of
826e4b17023SJohn Marino      the limit, whichever is larger.  If GCC does hit the data limit,
827e4b17023SJohn Marino      compilation will fail, so this tries to be conservative.  */
828e4b17023SJohn Marino   limit_kbytes = MAX (0, limit_kbytes - MAX (limit_kbytes / 4, 20 * 1024));
829e4b17023SJohn Marino   limit_kbytes = (limit_kbytes * 100) / (110 + ggc_min_expand_heuristic ());
830e4b17023SJohn Marino   phys_kbytes = MIN (phys_kbytes, limit_kbytes);
831e4b17023SJohn Marino 
832e4b17023SJohn Marino   phys_kbytes = MAX (phys_kbytes, 4 * 1024);
833e4b17023SJohn Marino   phys_kbytes = MIN (phys_kbytes, 128 * 1024);
834e4b17023SJohn Marino 
835e4b17023SJohn Marino   return phys_kbytes;
836e4b17023SJohn Marino }
837e4b17023SJohn Marino #endif
838e4b17023SJohn Marino 
839e4b17023SJohn Marino void
init_ggc_heuristics(void)840e4b17023SJohn Marino init_ggc_heuristics (void)
841e4b17023SJohn Marino {
842e4b17023SJohn Marino #if !defined ENABLE_GC_CHECKING && !defined ENABLE_GC_ALWAYS_COLLECT
843e4b17023SJohn Marino   set_default_param_value (GGC_MIN_EXPAND, ggc_min_expand_heuristic ());
844e4b17023SJohn Marino   set_default_param_value (GGC_MIN_HEAPSIZE, ggc_min_heapsize_heuristic ());
845e4b17023SJohn Marino #endif
846e4b17023SJohn Marino }
847e4b17023SJohn Marino 
848e4b17023SJohn Marino #ifdef GATHER_STATISTICS
849e4b17023SJohn Marino 
850e4b17023SJohn Marino /* Datastructure used to store per-call-site statistics.  */
851e4b17023SJohn Marino struct loc_descriptor
852e4b17023SJohn Marino {
853e4b17023SJohn Marino   const char *file;
854e4b17023SJohn Marino   int line;
855e4b17023SJohn Marino   const char *function;
856e4b17023SJohn Marino   int times;
857e4b17023SJohn Marino   size_t allocated;
858e4b17023SJohn Marino   size_t overhead;
859e4b17023SJohn Marino   size_t freed;
860e4b17023SJohn Marino   size_t collected;
861e4b17023SJohn Marino };
862e4b17023SJohn Marino 
863e4b17023SJohn Marino /* Hashtable used for statistics.  */
864e4b17023SJohn Marino static htab_t loc_hash;
865e4b17023SJohn Marino 
866e4b17023SJohn Marino /* Hash table helpers functions.  */
867e4b17023SJohn Marino static hashval_t
hash_descriptor(const void * p)868e4b17023SJohn Marino hash_descriptor (const void *p)
869e4b17023SJohn Marino {
870e4b17023SJohn Marino   const struct loc_descriptor *const d = (const struct loc_descriptor *) p;
871e4b17023SJohn Marino 
872e4b17023SJohn Marino   return htab_hash_pointer (d->function) | d->line;
873e4b17023SJohn Marino }
874e4b17023SJohn Marino 
875e4b17023SJohn Marino static int
eq_descriptor(const void * p1,const void * p2)876e4b17023SJohn Marino eq_descriptor (const void *p1, const void *p2)
877e4b17023SJohn Marino {
878e4b17023SJohn Marino   const struct loc_descriptor *const d = (const struct loc_descriptor *) p1;
879e4b17023SJohn Marino   const struct loc_descriptor *const d2 = (const struct loc_descriptor *) p2;
880e4b17023SJohn Marino 
881e4b17023SJohn Marino   return (d->file == d2->file && d->line == d2->line
882e4b17023SJohn Marino 	  && d->function == d2->function);
883e4b17023SJohn Marino }
884e4b17023SJohn Marino 
885e4b17023SJohn Marino /* Hashtable converting address of allocated field to loc descriptor.  */
886e4b17023SJohn Marino static htab_t ptr_hash;
887e4b17023SJohn Marino struct ptr_hash_entry
888e4b17023SJohn Marino {
889e4b17023SJohn Marino   void *ptr;
890e4b17023SJohn Marino   struct loc_descriptor *loc;
891e4b17023SJohn Marino   size_t size;
892e4b17023SJohn Marino };
893e4b17023SJohn Marino 
894e4b17023SJohn Marino /* Hash table helpers functions.  */
895e4b17023SJohn Marino static hashval_t
hash_ptr(const void * p)896e4b17023SJohn Marino hash_ptr (const void *p)
897e4b17023SJohn Marino {
898e4b17023SJohn Marino   const struct ptr_hash_entry *const d = (const struct ptr_hash_entry *) p;
899e4b17023SJohn Marino 
900e4b17023SJohn Marino   return htab_hash_pointer (d->ptr);
901e4b17023SJohn Marino }
902e4b17023SJohn Marino 
903e4b17023SJohn Marino static int
eq_ptr(const void * p1,const void * p2)904e4b17023SJohn Marino eq_ptr (const void *p1, const void *p2)
905e4b17023SJohn Marino {
906e4b17023SJohn Marino   const struct ptr_hash_entry *const p = (const struct ptr_hash_entry *) p1;
907e4b17023SJohn Marino 
908e4b17023SJohn Marino   return (p->ptr == p2);
909e4b17023SJohn Marino }
910e4b17023SJohn Marino 
911e4b17023SJohn Marino /* Return descriptor for given call site, create new one if needed.  */
912e4b17023SJohn Marino static struct loc_descriptor *
loc_descriptor(const char * name,int line,const char * function)913e4b17023SJohn Marino loc_descriptor (const char *name, int line, const char *function)
914e4b17023SJohn Marino {
915e4b17023SJohn Marino   struct loc_descriptor loc;
916e4b17023SJohn Marino   struct loc_descriptor **slot;
917e4b17023SJohn Marino 
918e4b17023SJohn Marino   loc.file = name;
919e4b17023SJohn Marino   loc.line = line;
920e4b17023SJohn Marino   loc.function = function;
921e4b17023SJohn Marino   if (!loc_hash)
922e4b17023SJohn Marino     loc_hash = htab_create (10, hash_descriptor, eq_descriptor, NULL);
923e4b17023SJohn Marino 
924e4b17023SJohn Marino   slot = (struct loc_descriptor **) htab_find_slot (loc_hash, &loc, INSERT);
925e4b17023SJohn Marino   if (*slot)
926e4b17023SJohn Marino     return *slot;
927e4b17023SJohn Marino   *slot = XCNEW (struct loc_descriptor);
928e4b17023SJohn Marino   (*slot)->file = name;
929e4b17023SJohn Marino   (*slot)->line = line;
930e4b17023SJohn Marino   (*slot)->function = function;
931e4b17023SJohn Marino   return *slot;
932e4b17023SJohn Marino }
933e4b17023SJohn Marino 
934e4b17023SJohn Marino /* Record ALLOCATED and OVERHEAD bytes to descriptor NAME:LINE (FUNCTION).  */
935e4b17023SJohn Marino void
ggc_record_overhead(size_t allocated,size_t overhead,void * ptr,const char * name,int line,const char * function)936e4b17023SJohn Marino ggc_record_overhead (size_t allocated, size_t overhead, void *ptr,
937e4b17023SJohn Marino 		     const char *name, int line, const char *function)
938e4b17023SJohn Marino {
939e4b17023SJohn Marino   struct loc_descriptor *loc = loc_descriptor (name, line, function);
940e4b17023SJohn Marino   struct ptr_hash_entry *p = XNEW (struct ptr_hash_entry);
941e4b17023SJohn Marino   PTR *slot;
942e4b17023SJohn Marino 
943e4b17023SJohn Marino   p->ptr = ptr;
944e4b17023SJohn Marino   p->loc = loc;
945e4b17023SJohn Marino   p->size = allocated + overhead;
946e4b17023SJohn Marino   if (!ptr_hash)
947e4b17023SJohn Marino     ptr_hash = htab_create (10, hash_ptr, eq_ptr, NULL);
948e4b17023SJohn Marino   slot = htab_find_slot_with_hash (ptr_hash, ptr, htab_hash_pointer (ptr), INSERT);
949e4b17023SJohn Marino   gcc_assert (!*slot);
950e4b17023SJohn Marino   *slot = p;
951e4b17023SJohn Marino 
952e4b17023SJohn Marino   loc->times++;
953e4b17023SJohn Marino   loc->allocated+=allocated;
954e4b17023SJohn Marino   loc->overhead+=overhead;
955e4b17023SJohn Marino }
956e4b17023SJohn Marino 
957e4b17023SJohn Marino /* Helper function for prune_overhead_list.  See if SLOT is still marked and
958e4b17023SJohn Marino    remove it from hashtable if it is not.  */
959e4b17023SJohn Marino static int
ggc_prune_ptr(void ** slot,void * b ATTRIBUTE_UNUSED)960e4b17023SJohn Marino ggc_prune_ptr (void **slot, void *b ATTRIBUTE_UNUSED)
961e4b17023SJohn Marino {
962e4b17023SJohn Marino   struct ptr_hash_entry *p = (struct ptr_hash_entry *) *slot;
963e4b17023SJohn Marino   if (!ggc_marked_p (p->ptr))
964e4b17023SJohn Marino     {
965e4b17023SJohn Marino       p->loc->collected += p->size;
966e4b17023SJohn Marino       htab_clear_slot (ptr_hash, slot);
967e4b17023SJohn Marino       free (p);
968e4b17023SJohn Marino     }
969e4b17023SJohn Marino   return 1;
970e4b17023SJohn Marino }
971e4b17023SJohn Marino 
972e4b17023SJohn Marino /* After live values has been marked, walk all recorded pointers and see if
973e4b17023SJohn Marino    they are still live.  */
974e4b17023SJohn Marino void
ggc_prune_overhead_list(void)975e4b17023SJohn Marino ggc_prune_overhead_list (void)
976e4b17023SJohn Marino {
977e4b17023SJohn Marino   htab_traverse (ptr_hash, ggc_prune_ptr, NULL);
978e4b17023SJohn Marino }
979e4b17023SJohn Marino 
980e4b17023SJohn Marino /* Notice that the pointer has been freed.  */
981e4b17023SJohn Marino void
ggc_free_overhead(void * ptr)982e4b17023SJohn Marino ggc_free_overhead (void *ptr)
983e4b17023SJohn Marino {
984e4b17023SJohn Marino   PTR *slot = htab_find_slot_with_hash (ptr_hash, ptr, htab_hash_pointer (ptr),
985e4b17023SJohn Marino 					NO_INSERT);
986e4b17023SJohn Marino   struct ptr_hash_entry *p;
987e4b17023SJohn Marino   /* The pointer might be not found if a PCH read happened between allocation
988e4b17023SJohn Marino      and ggc_free () call.  FIXME: account memory properly in the presence of
989e4b17023SJohn Marino      PCH. */
990e4b17023SJohn Marino   if (!slot)
991e4b17023SJohn Marino       return;
992e4b17023SJohn Marino   p = (struct ptr_hash_entry *) *slot;
993e4b17023SJohn Marino   p->loc->freed += p->size;
994e4b17023SJohn Marino   htab_clear_slot (ptr_hash, slot);
995e4b17023SJohn Marino   free (p);
996e4b17023SJohn Marino }
997e4b17023SJohn Marino 
998e4b17023SJohn Marino /* Helper for qsort; sort descriptors by amount of memory consumed.  */
999e4b17023SJohn Marino static int
final_cmp_statistic(const void * loc1,const void * loc2)1000e4b17023SJohn Marino final_cmp_statistic (const void *loc1, const void *loc2)
1001e4b17023SJohn Marino {
1002e4b17023SJohn Marino   const struct loc_descriptor *const l1 =
1003e4b17023SJohn Marino     *(const struct loc_descriptor *const *) loc1;
1004e4b17023SJohn Marino   const struct loc_descriptor *const l2 =
1005e4b17023SJohn Marino     *(const struct loc_descriptor *const *) loc2;
1006e4b17023SJohn Marino   long diff;
1007e4b17023SJohn Marino   diff = ((long)(l1->allocated + l1->overhead - l1->freed) -
1008e4b17023SJohn Marino 	  (l2->allocated + l2->overhead - l2->freed));
1009e4b17023SJohn Marino   return diff > 0 ? 1 : diff < 0 ? -1 : 0;
1010e4b17023SJohn Marino }
1011e4b17023SJohn Marino 
1012e4b17023SJohn Marino /* Helper for qsort; sort descriptors by amount of memory consumed.  */
1013e4b17023SJohn Marino static int
cmp_statistic(const void * loc1,const void * loc2)1014e4b17023SJohn Marino cmp_statistic (const void *loc1, const void *loc2)
1015e4b17023SJohn Marino {
1016e4b17023SJohn Marino   const struct loc_descriptor *const l1 =
1017e4b17023SJohn Marino     *(const struct loc_descriptor *const *) loc1;
1018e4b17023SJohn Marino   const struct loc_descriptor *const l2 =
1019e4b17023SJohn Marino     *(const struct loc_descriptor *const *) loc2;
1020e4b17023SJohn Marino   long diff;
1021e4b17023SJohn Marino 
1022e4b17023SJohn Marino   diff = ((long)(l1->allocated + l1->overhead - l1->freed - l1->collected) -
1023e4b17023SJohn Marino 	  (l2->allocated + l2->overhead - l2->freed - l2->collected));
1024e4b17023SJohn Marino   if (diff)
1025e4b17023SJohn Marino     return diff > 0 ? 1 : diff < 0 ? -1 : 0;
1026e4b17023SJohn Marino   diff =  ((long)(l1->allocated + l1->overhead - l1->freed) -
1027e4b17023SJohn Marino 	   (l2->allocated + l2->overhead - l2->freed));
1028e4b17023SJohn Marino   return diff > 0 ? 1 : diff < 0 ? -1 : 0;
1029e4b17023SJohn Marino }
1030e4b17023SJohn Marino 
1031e4b17023SJohn Marino /* Collect array of the descriptors from hashtable.  */
1032e4b17023SJohn Marino static struct loc_descriptor **loc_array;
1033e4b17023SJohn Marino static int
add_statistics(void ** slot,void * b)1034e4b17023SJohn Marino add_statistics (void **slot, void *b)
1035e4b17023SJohn Marino {
1036e4b17023SJohn Marino   int *n = (int *)b;
1037e4b17023SJohn Marino   loc_array[*n] = (struct loc_descriptor *) *slot;
1038e4b17023SJohn Marino   (*n)++;
1039e4b17023SJohn Marino   return 1;
1040e4b17023SJohn Marino }
1041e4b17023SJohn Marino 
1042e4b17023SJohn Marino /* Dump per-site memory statistics.  */
1043e4b17023SJohn Marino #endif
1044e4b17023SJohn Marino void
dump_ggc_loc_statistics(bool final ATTRIBUTE_UNUSED)1045e4b17023SJohn Marino dump_ggc_loc_statistics (bool final ATTRIBUTE_UNUSED)
1046e4b17023SJohn Marino {
1047e4b17023SJohn Marino #ifdef GATHER_STATISTICS
1048e4b17023SJohn Marino   int nentries = 0;
1049e4b17023SJohn Marino   char s[4096];
1050e4b17023SJohn Marino   size_t collected = 0, freed = 0, allocated = 0, overhead = 0, times = 0;
1051e4b17023SJohn Marino   int i;
1052e4b17023SJohn Marino 
1053e4b17023SJohn Marino   ggc_force_collect = true;
1054e4b17023SJohn Marino   ggc_collect ();
1055e4b17023SJohn Marino 
1056e4b17023SJohn Marino   loc_array = XCNEWVEC (struct loc_descriptor *, loc_hash->n_elements);
1057e4b17023SJohn Marino   fprintf (stderr, "-------------------------------------------------------\n");
1058e4b17023SJohn Marino   fprintf (stderr, "\n%-48s %10s       %10s       %10s       %10s       %10s\n",
1059e4b17023SJohn Marino 	   "source location", "Garbage", "Freed", "Leak", "Overhead", "Times");
1060e4b17023SJohn Marino   fprintf (stderr, "-------------------------------------------------------\n");
1061e4b17023SJohn Marino   htab_traverse (loc_hash, add_statistics, &nentries);
1062e4b17023SJohn Marino   qsort (loc_array, nentries, sizeof (*loc_array),
1063e4b17023SJohn Marino 	 final ? final_cmp_statistic : cmp_statistic);
1064e4b17023SJohn Marino   for (i = 0; i < nentries; i++)
1065e4b17023SJohn Marino     {
1066e4b17023SJohn Marino       struct loc_descriptor *d = loc_array[i];
1067e4b17023SJohn Marino       allocated += d->allocated;
1068e4b17023SJohn Marino       times += d->times;
1069e4b17023SJohn Marino       freed += d->freed;
1070e4b17023SJohn Marino       collected += d->collected;
1071e4b17023SJohn Marino       overhead += d->overhead;
1072e4b17023SJohn Marino     }
1073e4b17023SJohn Marino   for (i = 0; i < nentries; i++)
1074e4b17023SJohn Marino     {
1075e4b17023SJohn Marino       struct loc_descriptor *d = loc_array[i];
1076e4b17023SJohn Marino       if (d->allocated)
1077e4b17023SJohn Marino 	{
1078e4b17023SJohn Marino 	  const char *s1 = d->file;
1079e4b17023SJohn Marino 	  const char *s2;
1080e4b17023SJohn Marino 	  while ((s2 = strstr (s1, "gcc/")))
1081e4b17023SJohn Marino 	    s1 = s2 + 4;
1082e4b17023SJohn Marino 	  sprintf (s, "%s:%i (%s)", s1, d->line, d->function);
1083e4b17023SJohn Marino 	  s[48] = 0;
1084e4b17023SJohn Marino 	  fprintf (stderr, "%-48s %10li:%4.1f%% %10li:%4.1f%% %10li:%4.1f%% %10li:%4.1f%% %10li\n", s,
1085e4b17023SJohn Marino 		   (long)d->collected,
1086e4b17023SJohn Marino 		   (d->collected) * 100.0 / collected,
1087e4b17023SJohn Marino 		   (long)d->freed,
1088e4b17023SJohn Marino 		   (d->freed) * 100.0 / freed,
1089e4b17023SJohn Marino 		   (long)(d->allocated + d->overhead - d->freed - d->collected),
1090e4b17023SJohn Marino 		   (d->allocated + d->overhead - d->freed - d->collected) * 100.0
1091e4b17023SJohn Marino 		   / (allocated + overhead - freed - collected),
1092e4b17023SJohn Marino 		   (long)d->overhead,
1093e4b17023SJohn Marino 		   d->overhead * 100.0 / overhead,
1094e4b17023SJohn Marino 		   (long)d->times);
1095e4b17023SJohn Marino 	}
1096e4b17023SJohn Marino     }
1097e4b17023SJohn Marino   fprintf (stderr, "%-48s %10ld       %10ld       %10ld       %10ld       %10ld\n",
1098e4b17023SJohn Marino 	   "Total", (long)collected, (long)freed,
1099e4b17023SJohn Marino 	   (long)(allocated + overhead - freed - collected), (long)overhead,
1100e4b17023SJohn Marino 	   (long)times);
1101e4b17023SJohn Marino   fprintf (stderr, "%-48s %10s       %10s       %10s       %10s       %10s\n",
1102e4b17023SJohn Marino 	   "source location", "Garbage", "Freed", "Leak", "Overhead", "Times");
1103e4b17023SJohn Marino   fprintf (stderr, "-------------------------------------------------------\n");
1104e4b17023SJohn Marino   ggc_force_collect = false;
1105e4b17023SJohn Marino #endif
1106e4b17023SJohn Marino }
1107