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