190075Sobrien/* Simple garbage collection for the GNU compiler.
2169689Skan   Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
3132718Skan   Free Software Foundation, Inc.
490075Sobrien
590075SobrienThis file is part of GCC.
690075Sobrien
790075SobrienGCC is free software; you can redistribute it and/or modify it under
890075Sobrienthe terms of the GNU General Public License as published by the Free
990075SobrienSoftware Foundation; either version 2, or (at your option) any later
1090075Sobrienversion.
1190075Sobrien
1290075SobrienGCC is distributed in the hope that it will be useful, but WITHOUT ANY
1390075SobrienWARRANTY; without even the implied warranty of MERCHANTABILITY or
1490075SobrienFITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1590075Sobrienfor more details.
1690075Sobrien
1790075SobrienYou should have received a copy of the GNU General Public License
1890075Sobrienalong with GCC; see the file COPYING.  If not, write to the Free
19169689SkanSoftware Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
20169689Skan02110-1301, USA.  */
2190075Sobrien
2290075Sobrien/* Generic garbage collection (GC) functions and data, not specific to
2390075Sobrien   any particular GC implementation.  */
2490075Sobrien
2590075Sobrien#include "config.h"
2690075Sobrien#include "system.h"
27132718Skan#include "coretypes.h"
2890075Sobrien#include "hashtab.h"
2990075Sobrien#include "ggc.h"
30132718Skan#include "toplev.h"
31117395Skan#include "params.h"
32132718Skan#include "hosthooks.h"
33161651Skan#include "hosthooks-def.h"
34132718Skan
35117395Skan#ifdef HAVE_SYS_RESOURCE_H
36117395Skan# include <sys/resource.h>
37117395Skan#endif
38132718Skan
39132718Skan#ifdef HAVE_MMAP_FILE
40132718Skan# include <sys/mman.h>
41132718Skan# ifdef HAVE_MINCORE
42132718Skan/* This is on Solaris.  */
43132718Skan#  include <sys/types.h>
44132718Skan# endif
45132718Skan#endif
46132718Skan
47132718Skan#ifndef MAP_FAILED
48132718Skan# define MAP_FAILED ((void *)-1)
49132718Skan#endif
50132718Skan
51117395Skan#ifdef ENABLE_VALGRIND_CHECKING
52132718Skan# ifdef HAVE_VALGRIND_MEMCHECK_H
53132718Skan#  include <valgrind/memcheck.h>
54132718Skan# elif defined HAVE_MEMCHECK_H
55132718Skan#  include <memcheck.h>
56132718Skan# else
57132718Skan#  include <valgrind.h>
58132718Skan# endif
59117395Skan#else
60117395Skan/* Avoid #ifdef:s when we can help it.  */
61117395Skan#define VALGRIND_DISCARD(x)
62117395Skan#endif
6390075Sobrien
64169689Skan/* When set, ggc_collect will do collection.  */
65169689Skanbool ggc_force_collect;
66169689Skan
6790075Sobrien/* Statistics about the allocation.  */
6890075Sobrienstatic ggc_statistics *ggc_stats;
6990075Sobrien
70132718Skanstruct traversal_state;
7190075Sobrien
72132718Skanstatic int ggc_htab_delete (void **, void *);
73132718Skanstatic hashval_t saving_htab_hash (const void *);
74132718Skanstatic int saving_htab_eq (const void *, const void *);
75132718Skanstatic int call_count (void **, void *);
76132718Skanstatic int call_alloc (void **, void *);
77132718Skanstatic int compare_ptr_data (const void *, const void *);
78132718Skanstatic void relocate_ptrs (void *, void *);
79132718Skanstatic void write_pch_globals (const struct ggc_root_tab * const *tab,
80132718Skan			       struct traversal_state *state);
81132718Skanstatic double ggc_rlimit_bound (double);
82132718Skan
8390075Sobrien/* Maintain global roots that are preserved during GC.  */
8490075Sobrien
8590075Sobrien/* Process a slot of an htab by deleting it if it has not been marked.  */
8690075Sobrien
8790075Sobrienstatic int
88132718Skanggc_htab_delete (void **slot, void *info)
8990075Sobrien{
90117395Skan  const struct ggc_cache_tab *r = (const struct ggc_cache_tab *) info;
9190075Sobrien
9290075Sobrien  if (! (*r->marked_p) (*slot))
93117395Skan    htab_clear_slot (*r->base, slot);
94117395Skan  else
95117395Skan    (*r->cb) (*slot);
9690075Sobrien
9790075Sobrien  return 1;
9890075Sobrien}
9990075Sobrien
10090075Sobrien/* Iterate through all registered roots and mark each element.  */
10190075Sobrien
10290075Sobrienvoid
103132718Skanggc_mark_roots (void)
10490075Sobrien{
105117395Skan  const struct ggc_root_tab *const *rt;
106117395Skan  const struct ggc_root_tab *rti;
107117395Skan  const struct ggc_cache_tab *const *ct;
108117395Skan  const struct ggc_cache_tab *cti;
109117395Skan  size_t i;
11090075Sobrien
111117395Skan  for (rt = gt_ggc_deletable_rtab; *rt; rt++)
112117395Skan    for (rti = *rt; rti->base != NULL; rti++)
113117395Skan      memset (rti->base, 0, rti->stride);
114117395Skan
115117395Skan  for (rt = gt_ggc_rtab; *rt; rt++)
116117395Skan    for (rti = *rt; rti->base != NULL; rti++)
117117395Skan      for (i = 0; i < rti->nelt; i++)
118117395Skan	(*rti->cb)(*(void **)((char *)rti->base + rti->stride * i));
119117395Skan
120132718Skan  ggc_mark_stringpool ();
12190075Sobrien
12290075Sobrien  /* Now scan all hash tables that have objects which are to be deleted if
123117395Skan     they are not already marked.  */
124117395Skan  for (ct = gt_ggc_cache_rtab; *ct; ct++)
125117395Skan    for (cti = *ct; cti->base != NULL; cti++)
126117395Skan      if (*cti->base)
127132718Skan	{
128132718Skan	  ggc_set_mark (*cti->base);
129132718Skan	  htab_traverse_noresize (*cti->base, ggc_htab_delete, (void *) cti);
130132718Skan	  ggc_set_mark ((*cti->base)->entries);
131132718Skan	}
13290075Sobrien}
13390075Sobrien
134117395Skan/* Allocate a block of memory, then clear it.  */
135117395Skanvoid *
136169689Skanggc_alloc_cleared_stat (size_t size MEM_STAT_DECL)
13790075Sobrien{
138169689Skan  void *buf = ggc_alloc_stat (size PASS_MEM_STAT);
139117395Skan  memset (buf, 0, size);
140117395Skan  return buf;
14196263Sobrien}
14296263Sobrien
143117395Skan/* Resize a block of memory, possibly re-allocating it.  */
144117395Skanvoid *
145169689Skanggc_realloc_stat (void *x, size_t size MEM_STAT_DECL)
14696263Sobrien{
147117395Skan  void *r;
148117395Skan  size_t old_size;
14990075Sobrien
150117395Skan  if (x == NULL)
151169689Skan    return ggc_alloc_stat (size PASS_MEM_STAT);
15290075Sobrien
153117395Skan  old_size = ggc_get_size (x);
154169689Skan
155117395Skan  if (size <= old_size)
15690075Sobrien    {
157117395Skan      /* Mark the unwanted memory as unaccessible.  We also need to make
158117395Skan	 the "new" size accessible, since ggc_get_size returns the size of
159117395Skan	 the pool, not the size of the individually allocated object, the
160117395Skan	 size which was previously made accessible.  Unfortunately, we
161117395Skan	 don't know that previously allocated size.  Without that
162117395Skan	 knowledge we have to lose some initialization-tracking for the
163117395Skan	 old parts of the object.  An alternative is to mark the whole
164132718Skan	 old_size as reachable, but that would lose tracking of writes
165117395Skan	 after the end of the object (by small offsets).  Discard the
166117395Skan	 handle to avoid handle leak.  */
167117395Skan      VALGRIND_DISCARD (VALGRIND_MAKE_NOACCESS ((char *) x + size,
168117395Skan						old_size - size));
169117395Skan      VALGRIND_DISCARD (VALGRIND_MAKE_READABLE (x, size));
170117395Skan      return x;
17190075Sobrien    }
17290075Sobrien
173169689Skan  r = ggc_alloc_stat (size PASS_MEM_STAT);
17490075Sobrien
175117395Skan  /* Since ggc_get_size returns the size of the pool, not the size of the
176117395Skan     individually allocated object, we'd access parts of the old object
177117395Skan     that were marked invalid with the memcpy below.  We lose a bit of the
178117395Skan     initialization-tracking since some of it may be uninitialized.  */
179117395Skan  VALGRIND_DISCARD (VALGRIND_MAKE_READABLE (x, old_size));
18090075Sobrien
181117395Skan  memcpy (r, x, old_size);
18290075Sobrien
183117395Skan  /* The old object is not supposed to be used anymore.  */
184169689Skan  ggc_free (x);
18590075Sobrien
186117395Skan  return r;
18790075Sobrien}
18890075Sobrien
189117395Skan/* Like ggc_alloc_cleared, but performs a multiplication.  */
19090075Sobrienvoid *
191132718Skanggc_calloc (size_t s1, size_t s2)
19290075Sobrien{
193117395Skan  return ggc_alloc_cleared (s1 * s2);
19490075Sobrien}
19590075Sobrien
196132718Skan/* These are for splay_tree_new_ggc.  */
197132718Skanvoid *
198132718Skanggc_splay_alloc (int sz, void *nl)
199132718Skan{
200169689Skan  gcc_assert (!nl);
201132718Skan  return ggc_alloc (sz);
202132718Skan}
203132718Skan
204132718Skanvoid
205132718Skanggc_splay_dont_free (void * x ATTRIBUTE_UNUSED, void *nl)
206132718Skan{
207169689Skan  gcc_assert (!nl);
208132718Skan}
209132718Skan
21090075Sobrien/* Print statistics that are independent of the collector in use.  */
21190075Sobrien#define SCALE(x) ((unsigned long) ((x) < 1024*10 \
21290075Sobrien		  ? (x) \
21390075Sobrien		  : ((x) < 1024*1024*10 \
21490075Sobrien		     ? (x) / 1024 \
21590075Sobrien		     : (x) / (1024*1024))))
21690075Sobrien#define LABEL(x) ((x) < 1024*10 ? ' ' : ((x) < 1024*1024*10 ? 'k' : 'M'))
21790075Sobrien
21890075Sobrienvoid
219132718Skanggc_print_common_statistics (FILE *stream ATTRIBUTE_UNUSED,
220132718Skan			     ggc_statistics *stats)
22190075Sobrien{
22290075Sobrien  /* Set the pointer so that during collection we will actually gather
22390075Sobrien     the statistics.  */
22490075Sobrien  ggc_stats = stats;
22590075Sobrien
22690075Sobrien  /* Then do one collection to fill in the statistics.  */
22790075Sobrien  ggc_collect ();
22890075Sobrien
229132718Skan  /* At present, we don't really gather any interesting statistics.  */
230132718Skan
231132718Skan  /* Don't gather statistics any more.  */
232132718Skan  ggc_stats = NULL;
233132718Skan}
234132718Skan
235132718Skan/* Functions for saving and restoring GCable memory to disk.  */
236132718Skan
237132718Skanstatic htab_t saving_htab;
238132718Skan
239132718Skanstruct ptr_data
240132718Skan{
241132718Skan  void *obj;
242132718Skan  void *note_ptr_cookie;
243132718Skan  gt_note_pointers note_ptr_fn;
244132718Skan  gt_handle_reorder reorder_fn;
245132718Skan  size_t size;
246132718Skan  void *new_addr;
247169689Skan  enum gt_types_enum type;
248132718Skan};
249132718Skan
250132718Skan#define POINTER_HASH(x) (hashval_t)((long)x >> 3)
251132718Skan
252132718Skan/* Register an object in the hash table.  */
253132718Skan
254132718Skanint
255132718Skangt_pch_note_object (void *obj, void *note_ptr_cookie,
256169689Skan		    gt_note_pointers note_ptr_fn,
257169689Skan		    enum gt_types_enum type)
258132718Skan{
259132718Skan  struct ptr_data **slot;
260132718Skan
261132718Skan  if (obj == NULL || obj == (void *) 1)
262132718Skan    return 0;
263132718Skan
264132718Skan  slot = (struct ptr_data **)
265132718Skan    htab_find_slot_with_hash (saving_htab, obj, POINTER_HASH (obj),
266132718Skan			      INSERT);
267132718Skan  if (*slot != NULL)
26890075Sobrien    {
269169689Skan      gcc_assert ((*slot)->note_ptr_fn == note_ptr_fn
270169689Skan		  && (*slot)->note_ptr_cookie == note_ptr_cookie);
271132718Skan      return 0;
27290075Sobrien    }
273132718Skan
274132718Skan  *slot = xcalloc (sizeof (struct ptr_data), 1);
275132718Skan  (*slot)->obj = obj;
276132718Skan  (*slot)->note_ptr_fn = note_ptr_fn;
277132718Skan  (*slot)->note_ptr_cookie = note_ptr_cookie;
278132718Skan  if (note_ptr_fn == gt_pch_p_S)
279132718Skan    (*slot)->size = strlen (obj) + 1;
280132718Skan  else
281132718Skan    (*slot)->size = ggc_get_size (obj);
282169689Skan  (*slot)->type = type;
283132718Skan  return 1;
284132718Skan}
285132718Skan
286132718Skan/* Register an object in the hash table.  */
287132718Skan
288132718Skanvoid
289132718Skangt_pch_note_reorder (void *obj, void *note_ptr_cookie,
290132718Skan		     gt_handle_reorder reorder_fn)
291132718Skan{
292132718Skan  struct ptr_data *data;
293132718Skan
294132718Skan  if (obj == NULL || obj == (void *) 1)
295132718Skan    return;
296132718Skan
297132718Skan  data = htab_find_with_hash (saving_htab, obj, POINTER_HASH (obj));
298169689Skan  gcc_assert (data && data->note_ptr_cookie == note_ptr_cookie);
299132718Skan
300132718Skan  data->reorder_fn = reorder_fn;
301132718Skan}
302132718Skan
303132718Skan/* Hash and equality functions for saving_htab, callbacks for htab_create.  */
304132718Skan
305132718Skanstatic hashval_t
306132718Skansaving_htab_hash (const void *p)
307132718Skan{
308132718Skan  return POINTER_HASH (((struct ptr_data *)p)->obj);
309132718Skan}
310132718Skan
311132718Skanstatic int
312132718Skansaving_htab_eq (const void *p1, const void *p2)
313132718Skan{
314132718Skan  return ((struct ptr_data *)p1)->obj == p2;
315132718Skan}
316132718Skan
317132718Skan/* Handy state for the traversal functions.  */
318132718Skan
319132718Skanstruct traversal_state
320132718Skan{
321132718Skan  FILE *f;
322132718Skan  struct ggc_pch_data *d;
323132718Skan  size_t count;
324132718Skan  struct ptr_data **ptrs;
325132718Skan  size_t ptrs_i;
326132718Skan};
327132718Skan
328132718Skan/* Callbacks for htab_traverse.  */
329132718Skan
330132718Skanstatic int
331132718Skancall_count (void **slot, void *state_p)
332132718Skan{
333132718Skan  struct ptr_data *d = (struct ptr_data *)*slot;
334132718Skan  struct traversal_state *state = (struct traversal_state *)state_p;
335132718Skan
336169689Skan  ggc_pch_count_object (state->d, d->obj, d->size,
337169689Skan			d->note_ptr_fn == gt_pch_p_S,
338169689Skan			d->type);
339132718Skan  state->count++;
340132718Skan  return 1;
341132718Skan}
342132718Skan
343132718Skanstatic int
344132718Skancall_alloc (void **slot, void *state_p)
345132718Skan{
346132718Skan  struct ptr_data *d = (struct ptr_data *)*slot;
347132718Skan  struct traversal_state *state = (struct traversal_state *)state_p;
348132718Skan
349169689Skan  d->new_addr = ggc_pch_alloc_object (state->d, d->obj, d->size,
350169689Skan				      d->note_ptr_fn == gt_pch_p_S,
351169689Skan				      d->type);
352132718Skan  state->ptrs[state->ptrs_i++] = d;
353132718Skan  return 1;
354132718Skan}
355132718Skan
356132718Skan/* Callback for qsort.  */
357132718Skan
358132718Skanstatic int
359132718Skancompare_ptr_data (const void *p1_p, const void *p2_p)
360132718Skan{
361132718Skan  struct ptr_data *p1 = *(struct ptr_data *const *)p1_p;
362132718Skan  struct ptr_data *p2 = *(struct ptr_data *const *)p2_p;
363132718Skan  return (((size_t)p1->new_addr > (size_t)p2->new_addr)
364132718Skan	  - ((size_t)p1->new_addr < (size_t)p2->new_addr));
365132718Skan}
366132718Skan
367132718Skan/* Callbacks for note_ptr_fn.  */
368132718Skan
369132718Skanstatic void
370132718Skanrelocate_ptrs (void *ptr_p, void *state_p)
371132718Skan{
372132718Skan  void **ptr = (void **)ptr_p;
373132718Skan  struct traversal_state *state ATTRIBUTE_UNUSED
374132718Skan    = (struct traversal_state *)state_p;
375132718Skan  struct ptr_data *result;
376132718Skan
377132718Skan  if (*ptr == NULL || *ptr == (void *)1)
378132718Skan    return;
379132718Skan
380132718Skan  result = htab_find_with_hash (saving_htab, *ptr, POINTER_HASH (*ptr));
381169689Skan  gcc_assert (result);
382132718Skan  *ptr = result->new_addr;
383132718Skan}
384132718Skan
385132718Skan/* Write out, after relocation, the pointers in TAB.  */
386132718Skanstatic void
387132718Skanwrite_pch_globals (const struct ggc_root_tab * const *tab,
388132718Skan		   struct traversal_state *state)
389132718Skan{
390132718Skan  const struct ggc_root_tab *const *rt;
391132718Skan  const struct ggc_root_tab *rti;
392132718Skan  size_t i;
393132718Skan
394132718Skan  for (rt = tab; *rt; rt++)
395132718Skan    for (rti = *rt; rti->base != NULL; rti++)
396132718Skan      for (i = 0; i < rti->nelt; i++)
397132718Skan	{
398132718Skan	  void *ptr = *(void **)((char *)rti->base + rti->stride * i);
399132718Skan	  struct ptr_data *new_ptr;
400132718Skan	  if (ptr == NULL || ptr == (void *)1)
401132718Skan	    {
402132718Skan	      if (fwrite (&ptr, sizeof (void *), 1, state->f)
403132718Skan		  != 1)
404132718Skan		fatal_error ("can't write PCH file: %m");
405132718Skan	    }
406132718Skan	  else
407132718Skan	    {
408132718Skan	      new_ptr = htab_find_with_hash (saving_htab, ptr,
409132718Skan					     POINTER_HASH (ptr));
410132718Skan	      if (fwrite (&new_ptr->new_addr, sizeof (void *), 1, state->f)
411132718Skan		  != 1)
412132718Skan		fatal_error ("can't write PCH file: %m");
413132718Skan	    }
414132718Skan	}
415132718Skan}
416132718Skan
417132718Skan/* Hold the information we need to mmap the file back in.  */
418132718Skan
419132718Skanstruct mmap_info
420132718Skan{
421132718Skan  size_t offset;
422132718Skan  size_t size;
423132718Skan  void *preferred_base;
424132718Skan};
425132718Skan
426132718Skan/* Write out the state of the compiler to F.  */
427132718Skan
428132718Skanvoid
429132718Skangt_pch_save (FILE *f)
430132718Skan{
431132718Skan  const struct ggc_root_tab *const *rt;
432132718Skan  const struct ggc_root_tab *rti;
433132718Skan  size_t i;
434132718Skan  struct traversal_state state;
435132718Skan  char *this_object = NULL;
436132718Skan  size_t this_object_size = 0;
437132718Skan  struct mmap_info mmi;
438169689Skan  const size_t mmap_offset_alignment = host_hooks.gt_pch_alloc_granularity();
439132718Skan
440132718Skan  gt_pch_save_stringpool ();
441132718Skan
442132718Skan  saving_htab = htab_create (50000, saving_htab_hash, saving_htab_eq, free);
443132718Skan
444132718Skan  for (rt = gt_ggc_rtab; *rt; rt++)
445132718Skan    for (rti = *rt; rti->base != NULL; rti++)
446132718Skan      for (i = 0; i < rti->nelt; i++)
447132718Skan	(*rti->pchw)(*(void **)((char *)rti->base + rti->stride * i));
448132718Skan
449132718Skan  for (rt = gt_pch_cache_rtab; *rt; rt++)
450132718Skan    for (rti = *rt; rti->base != NULL; rti++)
451132718Skan      for (i = 0; i < rti->nelt; i++)
452132718Skan	(*rti->pchw)(*(void **)((char *)rti->base + rti->stride * i));
453132718Skan
454132718Skan  /* Prepare the objects for writing, determine addresses and such.  */
455132718Skan  state.f = f;
456132718Skan  state.d = init_ggc_pch();
457132718Skan  state.count = 0;
458132718Skan  htab_traverse (saving_htab, call_count, &state);
459132718Skan
460132718Skan  mmi.size = ggc_pch_total_size (state.d);
461132718Skan
462132718Skan  /* Try to arrange things so that no relocation is necessary, but
463132718Skan     don't try very hard.  On most platforms, this will always work,
464132718Skan     and on the rest it's a lot of work to do better.
465132718Skan     (The extra work goes in HOST_HOOKS_GT_PCH_GET_ADDRESS and
466132718Skan     HOST_HOOKS_GT_PCH_USE_ADDRESS.)  */
467161651Skan  mmi.preferred_base = host_hooks.gt_pch_get_address (mmi.size, fileno (f));
468132718Skan
469132718Skan  ggc_pch_this_base (state.d, mmi.preferred_base);
47090075Sobrien
471169689Skan  state.ptrs = XNEWVEC (struct ptr_data *, state.count);
472132718Skan  state.ptrs_i = 0;
473132718Skan  htab_traverse (saving_htab, call_alloc, &state);
474132718Skan  qsort (state.ptrs, state.count, sizeof (*state.ptrs), compare_ptr_data);
47590075Sobrien
476132718Skan  /* Write out all the scalar variables.  */
477132718Skan  for (rt = gt_pch_scalar_rtab; *rt; rt++)
478132718Skan    for (rti = *rt; rti->base != NULL; rti++)
479132718Skan      if (fwrite (rti->base, rti->stride, 1, f) != 1)
480132718Skan	fatal_error ("can't write PCH file: %m");
481132718Skan
482132718Skan  /* Write out all the global pointers, after translation.  */
483132718Skan  write_pch_globals (gt_ggc_rtab, &state);
484132718Skan  write_pch_globals (gt_pch_cache_rtab, &state);
485132718Skan
486169689Skan  /* Pad the PCH file so that the mmapped area starts on an allocation
487169689Skan     granularity (usually page) boundary.  */
488132718Skan  {
489132718Skan    long o;
490132718Skan    o = ftell (state.f) + sizeof (mmi);
491132718Skan    if (o == -1)
492132718Skan      fatal_error ("can't get position in PCH file: %m");
493169689Skan    mmi.offset = mmap_offset_alignment - o % mmap_offset_alignment;
494169689Skan    if (mmi.offset == mmap_offset_alignment)
495132718Skan      mmi.offset = 0;
496132718Skan    mmi.offset += o;
497132718Skan  }
498132718Skan  if (fwrite (&mmi, sizeof (mmi), 1, state.f) != 1)
499132718Skan    fatal_error ("can't write PCH file: %m");
500132718Skan  if (mmi.offset != 0
501132718Skan      && fseek (state.f, mmi.offset, SEEK_SET) != 0)
502132718Skan    fatal_error ("can't write padding to PCH file: %m");
503132718Skan
504169689Skan  ggc_pch_prepare_write (state.d, state.f);
505169689Skan
506132718Skan  /* Actually write out the objects.  */
507132718Skan  for (i = 0; i < state.count; i++)
508132718Skan    {
509132718Skan      if (this_object_size < state.ptrs[i]->size)
510132718Skan	{
511132718Skan	  this_object_size = state.ptrs[i]->size;
512132718Skan	  this_object = xrealloc (this_object, this_object_size);
513132718Skan	}
514132718Skan      memcpy (this_object, state.ptrs[i]->obj, state.ptrs[i]->size);
515132718Skan      if (state.ptrs[i]->reorder_fn != NULL)
516132718Skan	state.ptrs[i]->reorder_fn (state.ptrs[i]->obj,
517132718Skan				   state.ptrs[i]->note_ptr_cookie,
518132718Skan				   relocate_ptrs, &state);
519132718Skan      state.ptrs[i]->note_ptr_fn (state.ptrs[i]->obj,
520132718Skan				  state.ptrs[i]->note_ptr_cookie,
521132718Skan				  relocate_ptrs, &state);
522132718Skan      ggc_pch_write_object (state.d, state.f, state.ptrs[i]->obj,
523161651Skan			    state.ptrs[i]->new_addr, state.ptrs[i]->size,
524161651Skan			    state.ptrs[i]->note_ptr_fn == gt_pch_p_S);
525132718Skan      if (state.ptrs[i]->note_ptr_fn != gt_pch_p_S)
526132718Skan	memcpy (state.ptrs[i]->obj, this_object, state.ptrs[i]->size);
527132718Skan    }
528132718Skan  ggc_pch_finish (state.d, state.f);
529132718Skan  gt_pch_fixup_stringpool ();
530132718Skan
531132718Skan  free (state.ptrs);
532132718Skan  htab_delete (saving_htab);
53390075Sobrien}
534117395Skan
535132718Skan/* Read the state of the compiler back in from F.  */
536132718Skan
537132718Skanvoid
538132718Skangt_pch_restore (FILE *f)
539132718Skan{
540132718Skan  const struct ggc_root_tab *const *rt;
541132718Skan  const struct ggc_root_tab *rti;
542132718Skan  size_t i;
543132718Skan  struct mmap_info mmi;
544161651Skan  int result;
545132718Skan
546132718Skan  /* Delete any deletable objects.  This makes ggc_pch_read much
547132718Skan     faster, as it can be sure that no GCable objects remain other
548132718Skan     than the ones just read in.  */
549132718Skan  for (rt = gt_ggc_deletable_rtab; *rt; rt++)
550132718Skan    for (rti = *rt; rti->base != NULL; rti++)
551132718Skan      memset (rti->base, 0, rti->stride);
552132718Skan
553132718Skan  /* Read in all the scalar variables.  */
554132718Skan  for (rt = gt_pch_scalar_rtab; *rt; rt++)
555132718Skan    for (rti = *rt; rti->base != NULL; rti++)
556132718Skan      if (fread (rti->base, rti->stride, 1, f) != 1)
557132718Skan	fatal_error ("can't read PCH file: %m");
558132718Skan
559132718Skan  /* Read in all the global pointers, in 6 easy loops.  */
560132718Skan  for (rt = gt_ggc_rtab; *rt; rt++)
561132718Skan    for (rti = *rt; rti->base != NULL; rti++)
562132718Skan      for (i = 0; i < rti->nelt; i++)
563132718Skan	if (fread ((char *)rti->base + rti->stride * i,
564132718Skan		   sizeof (void *), 1, f) != 1)
565132718Skan	  fatal_error ("can't read PCH file: %m");
566132718Skan
567132718Skan  for (rt = gt_pch_cache_rtab; *rt; rt++)
568132718Skan    for (rti = *rt; rti->base != NULL; rti++)
569132718Skan      for (i = 0; i < rti->nelt; i++)
570132718Skan	if (fread ((char *)rti->base + rti->stride * i,
571132718Skan		   sizeof (void *), 1, f) != 1)
572132718Skan	  fatal_error ("can't read PCH file: %m");
573132718Skan
574132718Skan  if (fread (&mmi, sizeof (mmi), 1, f) != 1)
575132718Skan    fatal_error ("can't read PCH file: %m");
576132718Skan
577161651Skan  result = host_hooks.gt_pch_use_address (mmi.preferred_base, mmi.size,
578161651Skan					  fileno (f), mmi.offset);
579161651Skan  if (result < 0)
580161651Skan    fatal_error ("had to relocate PCH");
581161651Skan  if (result == 0)
582132718Skan    {
583132718Skan      if (fseek (f, mmi.offset, SEEK_SET) != 0
584161651Skan	  || fread (mmi.preferred_base, mmi.size, 1, f) != 1)
585132718Skan	fatal_error ("can't read PCH file: %m");
586132718Skan    }
587132718Skan  else if (fseek (f, mmi.offset + mmi.size, SEEK_SET) != 0)
588132718Skan    fatal_error ("can't read PCH file: %m");
589132718Skan
590161651Skan  ggc_pch_read (f, mmi.preferred_base);
591132718Skan
592161651Skan  gt_pch_restore_stringpool ();
593161651Skan}
594132718Skan
595161651Skan/* Default version of HOST_HOOKS_GT_PCH_GET_ADDRESS when mmap is not present.
596161651Skan   Select no address whatsoever, and let gt_pch_save choose what it will with
597161651Skan   malloc, presumably.  */
598132718Skan
599161651Skanvoid *
600161651Skandefault_gt_pch_get_address (size_t size ATTRIBUTE_UNUSED,
601161651Skan			    int fd ATTRIBUTE_UNUSED)
602161651Skan{
603161651Skan  return NULL;
604161651Skan}
605132718Skan
606161651Skan/* Default version of HOST_HOOKS_GT_PCH_USE_ADDRESS when mmap is not present.
607161651Skan   Allocate SIZE bytes with malloc.  Return 0 if the address we got is the
608161651Skan   same as base, indicating that the memory has been allocated but needs to
609161651Skan   be read in from the file.  Return -1 if the address differs, to relocation
610161651Skan   of the PCH file would be required.  */
611161651Skan
612161651Skanint
613161651Skandefault_gt_pch_use_address (void *base, size_t size, int fd ATTRIBUTE_UNUSED,
614161651Skan			    size_t offset ATTRIBUTE_UNUSED)
615161651Skan{
616161651Skan  void *addr = xmalloc (size);
617161651Skan  return (addr == base) - 1;
618132718Skan}
619132718Skan
620169689Skan/* Default version of HOST_HOOKS_GT_PCH_GET_ADDRESS.   Return the
621169689Skan   alignment required for allocating virtual memory. Usually this is the
622169689Skan   same as pagesize.  */
623169689Skan
624169689Skansize_t
625169689Skandefault_gt_pch_alloc_granularity (void)
626169689Skan{
627169689Skan  return getpagesize();
628169689Skan}
629169689Skan
630161651Skan#if HAVE_MMAP_FILE
631161651Skan/* Default version of HOST_HOOKS_GT_PCH_GET_ADDRESS when mmap is present.
632161651Skan   We temporarily allocate SIZE bytes, and let the kernel place the data
633169689Skan   wherever it will.  If it worked, that's our spot, if not we're likely
634161651Skan   to be in trouble.  */
635169689Skan
636161651Skanvoid *
637161651Skanmmap_gt_pch_get_address (size_t size, int fd)
638161651Skan{
639161651Skan  void *ret;
640169689Skan
641161651Skan  ret = mmap (NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
642161651Skan  if (ret == (void *) MAP_FAILED)
643161651Skan    ret = NULL;
644161651Skan  else
645161651Skan    munmap (ret, size);
646169689Skan
647161651Skan  return ret;
648161651Skan}
649161651Skan
650161651Skan/* Default version of HOST_HOOKS_GT_PCH_USE_ADDRESS when mmap is present.
651161651Skan   Map SIZE bytes of FD+OFFSET at BASE.  Return 1 if we succeeded at
652161651Skan   mapping the data at BASE, -1 if we couldn't.
653169689Skan
654161651Skan   This version assumes that the kernel honors the START operand of mmap
655161651Skan   even without MAP_FIXED if START through START+SIZE are not currently
656161651Skan   mapped with something.  */
657169689Skan
658161651Skanint
659161651Skanmmap_gt_pch_use_address (void *base, size_t size, int fd, size_t offset)
660161651Skan{
661161651Skan  void *addr;
662169689Skan
663161651Skan  /* We're called with size == 0 if we're not planning to load a PCH
664161651Skan     file at all.  This allows the hook to free any static space that
665161651Skan     we might have allocated at link time.  */
666161651Skan  if (size == 0)
667161651Skan    return -1;
668169689Skan
669161651Skan  addr = mmap (base, size, PROT_READ | PROT_WRITE, MAP_PRIVATE,
670161651Skan	       fd, offset);
671161651Skan
672161651Skan  return addr == base ? 1 : -1;
673169689Skan}
674161651Skan#endif /* HAVE_MMAP_FILE */
675161651Skan
676169689Skan/* Modify the bound based on rlimits.  */
677117395Skanstatic double
678132718Skanggc_rlimit_bound (double limit)
679117395Skan{
680117395Skan#if defined(HAVE_GETRLIMIT)
681117395Skan  struct rlimit rlim;
682169689Skan# if defined (RLIMIT_AS)
683169689Skan  /* RLIMIT_AS is what POSIX says is the limit on mmap.  Presumably
684169689Skan     any OS which has RLIMIT_AS also has a working mmap that GCC will use.  */
685169689Skan  if (getrlimit (RLIMIT_AS, &rlim) == 0
686117395Skan      && rlim.rlim_cur != (rlim_t) RLIM_INFINITY
687117395Skan      && rlim.rlim_cur < limit)
688117395Skan    limit = rlim.rlim_cur;
689169689Skan# elif defined (RLIMIT_DATA)
690169689Skan  /* ... but some older OSs bound mmap based on RLIMIT_DATA, or we
691169689Skan     might be on an OS that has a broken mmap.  (Others don't bound
692169689Skan     mmap at all, apparently.)  */
693117395Skan  if (getrlimit (RLIMIT_DATA, &rlim) == 0
694117395Skan      && rlim.rlim_cur != (rlim_t) RLIM_INFINITY
695169689Skan      && rlim.rlim_cur < limit
696169689Skan      /* Darwin has this horribly bogus default setting of
697169689Skan	 RLIMIT_DATA, to 6144Kb.  No-one notices because RLIMIT_DATA
698169689Skan	 appears to be ignored.  Ignore such silliness.  If a limit
699169689Skan	 this small was actually effective for mmap, GCC wouldn't even
700169689Skan	 start up.  */
701169689Skan      && rlim.rlim_cur >= 8 * 1024 * 1024)
702117395Skan    limit = rlim.rlim_cur;
703169689Skan# endif /* RLIMIT_AS or RLIMIT_DATA */
704117395Skan#endif /* HAVE_GETRLIMIT */
705117395Skan
706117395Skan  return limit;
707117395Skan}
708117395Skan
709117395Skan/* Heuristic to set a default for GGC_MIN_EXPAND.  */
710117395Skanint
711132718Skanggc_min_expand_heuristic (void)
712117395Skan{
713117395Skan  double min_expand = physmem_total();
714117395Skan
715117395Skan  /* Adjust for rlimits.  */
716117395Skan  min_expand = ggc_rlimit_bound (min_expand);
717132718Skan
718117395Skan  /* The heuristic is a percentage equal to 30% + 70%*(RAM/1GB), yielding
719260311Spfg  APPLE LOCAL retune gc params 6124839
720260311Spfg     a lower bound of 30% and an upper bound of 150% (when RAM >= 1.7GB).  */
721117395Skan  min_expand /= 1024*1024*1024;
722117395Skan  min_expand *= 70;
723260311Spfg  /* APPLE LOCAL retune gc params 6124839 */
724260311Spfg  min_expand = MIN (min_expand, 120);
725117395Skan  min_expand += 30;
726117395Skan
727117395Skan  return min_expand;
728117395Skan}
729117395Skan
730117395Skan/* Heuristic to set a default for GGC_MIN_HEAPSIZE.  */
731117395Skanint
732260311Spfg/* APPLE LOCAL retune gc params 6124839 */
733260311Spfgggc_min_heapsize_heuristic (bool optimize)
734117395Skan{
735169689Skan  double phys_kbytes = physmem_total();
736169689Skan  double limit_kbytes = ggc_rlimit_bound (phys_kbytes * 2);
737117395Skan
738169689Skan  phys_kbytes /= 1024; /* Convert to Kbytes.  */
739169689Skan  limit_kbytes /= 1024;
740117395Skan
741117395Skan  /* The heuristic is RAM/8, with a lower bound of 4M and an upper
742117395Skan     bound of 128M (when RAM >= 1GB).  */
743169689Skan  phys_kbytes /= 8;
744117395Skan
745260311Spfg  /* APPLE LOCAL begin retune gc params 6124839 */
746260311Spfg
747260311Spfg  /* Additionally, on a multicore machine, we assume that we share the
748260311Spfg     memory with others reasonably equally.  */
749260311Spfg  phys_kbytes /= (double)ncpu_available() / (2 - optimize);
750260311Spfg  /* APPLE LOCAL end retune gc params 6124839 */
751260311Spfg
752169689Skan#if defined(HAVE_GETRLIMIT) && defined (RLIMIT_RSS)
753169689Skan  /* Try not to overrun the RSS limit while doing garbage collection.
754169689Skan     The RSS limit is only advisory, so no margin is subtracted.  */
755169689Skan {
756169689Skan   struct rlimit rlim;
757169689Skan   if (getrlimit (RLIMIT_RSS, &rlim) == 0
758169689Skan       && rlim.rlim_cur != (rlim_t) RLIM_INFINITY)
759169689Skan     phys_kbytes = MIN (phys_kbytes, rlim.rlim_cur / 1024);
760169689Skan }
761169689Skan# endif
762169689Skan
763169689Skan  /* Don't blindly run over our data limit; do GC at least when the
764169689Skan     *next* GC would be within 16Mb of the limit.  If GCC does hit the
765169689Skan     data limit, compilation will fail, so this tries to be
766169689Skan     conservative.  */
767169689Skan  limit_kbytes = MAX (0, limit_kbytes - 16 * 1024);
768169689Skan  limit_kbytes = (limit_kbytes * 100) / (110 + ggc_min_expand_heuristic());
769169689Skan  phys_kbytes = MIN (phys_kbytes, limit_kbytes);
770169689Skan
771169689Skan  phys_kbytes = MAX (phys_kbytes, 4 * 1024);
772169689Skan  phys_kbytes = MIN (phys_kbytes, 128 * 1024);
773169689Skan
774169689Skan  return phys_kbytes;
775117395Skan}
776117395Skan
777117395Skanvoid
778260311Spfg/* APPLE LOCAL retune gc params 6124839 */
779260311Spfginit_ggc_heuristics (bool optimize ATTRIBUTE_UNUSED)
780117395Skan{
781132718Skan#if !defined ENABLE_GC_CHECKING && !defined ENABLE_GC_ALWAYS_COLLECT
782117395Skan  set_param_value ("ggc-min-expand", ggc_min_expand_heuristic());
783260311Spfg  /* APPLE LOCAL retune gc params 6124839 */
784260311Spfg  set_param_value ("ggc-min-heapsize", ggc_min_heapsize_heuristic(optimize));
785117395Skan#endif
786117395Skan}
787169689Skan
788169689Skan#ifdef GATHER_STATISTICS
789169689Skan
790169689Skan/* Datastructure used to store per-call-site statistics.  */
791169689Skanstruct loc_descriptor
792169689Skan{
793169689Skan  const char *file;
794169689Skan  int line;
795169689Skan  const char *function;
796169689Skan  int times;
797169689Skan  size_t allocated;
798169689Skan  size_t overhead;
799169689Skan  size_t freed;
800169689Skan  size_t collected;
801169689Skan};
802169689Skan
803169689Skan/* Hashtable used for statistics.  */
804169689Skanstatic htab_t loc_hash;
805169689Skan
806169689Skan/* Hash table helpers functions.  */
807169689Skanstatic hashval_t
808169689Skanhash_descriptor (const void *p)
809169689Skan{
810169689Skan  const struct loc_descriptor *d = p;
811169689Skan
812169689Skan  return htab_hash_pointer (d->function) | d->line;
813169689Skan}
814169689Skan
815169689Skanstatic int
816169689Skaneq_descriptor (const void *p1, const void *p2)
817169689Skan{
818169689Skan  const struct loc_descriptor *d = p1;
819169689Skan  const struct loc_descriptor *d2 = p2;
820169689Skan
821169689Skan  return (d->file == d2->file && d->line == d2->line
822169689Skan	  && d->function == d2->function);
823169689Skan}
824169689Skan
825169689Skan/* Hashtable converting address of allocated field to loc descriptor.  */
826169689Skanstatic htab_t ptr_hash;
827169689Skanstruct ptr_hash_entry
828169689Skan{
829169689Skan  void *ptr;
830169689Skan  struct loc_descriptor *loc;
831169689Skan  size_t size;
832169689Skan};
833169689Skan
834169689Skan/* Hash table helpers functions.  */
835169689Skanstatic hashval_t
836169689Skanhash_ptr (const void *p)
837169689Skan{
838169689Skan  const struct ptr_hash_entry *d = p;
839169689Skan
840169689Skan  return htab_hash_pointer (d->ptr);
841169689Skan}
842169689Skan
843169689Skanstatic int
844169689Skaneq_ptr (const void *p1, const void *p2)
845169689Skan{
846169689Skan  const struct ptr_hash_entry *p = p1;
847169689Skan
848169689Skan  return (p->ptr == p2);
849169689Skan}
850169689Skan
851169689Skan/* Return descriptor for given call site, create new one if needed.  */
852169689Skanstatic struct loc_descriptor *
853169689Skanloc_descriptor (const char *name, int line, const char *function)
854169689Skan{
855169689Skan  struct loc_descriptor loc;
856169689Skan  struct loc_descriptor **slot;
857169689Skan
858169689Skan  loc.file = name;
859169689Skan  loc.line = line;
860169689Skan  loc.function = function;
861169689Skan  if (!loc_hash)
862169689Skan    loc_hash = htab_create (10, hash_descriptor, eq_descriptor, NULL);
863169689Skan
864169689Skan  slot = (struct loc_descriptor **) htab_find_slot (loc_hash, &loc, 1);
865169689Skan  if (*slot)
866169689Skan    return *slot;
867169689Skan  *slot = xcalloc (sizeof (**slot), 1);
868169689Skan  (*slot)->file = name;
869169689Skan  (*slot)->line = line;
870169689Skan  (*slot)->function = function;
871169689Skan  return *slot;
872169689Skan}
873169689Skan
874169689Skan/* Record ALLOCATED and OVERHEAD bytes to descriptor NAME:LINE (FUNCTION).  */
875169689Skanvoid
876169689Skanggc_record_overhead (size_t allocated, size_t overhead, void *ptr,
877169689Skan		     const char *name, int line, const char *function)
878169689Skan{
879169689Skan  struct loc_descriptor *loc = loc_descriptor (name, line, function);
880169689Skan  struct ptr_hash_entry *p = XNEW (struct ptr_hash_entry);
881169689Skan  PTR *slot;
882169689Skan
883169689Skan  p->ptr = ptr;
884169689Skan  p->loc = loc;
885169689Skan  p->size = allocated + overhead;
886169689Skan  if (!ptr_hash)
887169689Skan    ptr_hash = htab_create (10, hash_ptr, eq_ptr, NULL);
888169689Skan  slot = htab_find_slot_with_hash (ptr_hash, ptr, htab_hash_pointer (ptr), INSERT);
889169689Skan  gcc_assert (!*slot);
890169689Skan  *slot = p;
891169689Skan
892169689Skan  loc->times++;
893169689Skan  loc->allocated+=allocated;
894169689Skan  loc->overhead+=overhead;
895169689Skan}
896169689Skan
897169689Skan/* Helper function for prune_overhead_list.  See if SLOT is still marked and
898169689Skan   remove it from hashtable if it is not.  */
899169689Skanstatic int
900169689Skanggc_prune_ptr (void **slot, void *b ATTRIBUTE_UNUSED)
901169689Skan{
902169689Skan  struct ptr_hash_entry *p = *slot;
903169689Skan  if (!ggc_marked_p (p->ptr))
904169689Skan    {
905169689Skan      p->loc->collected += p->size;
906169689Skan      htab_clear_slot (ptr_hash, slot);
907169689Skan      free (p);
908169689Skan    }
909169689Skan  return 1;
910169689Skan}
911169689Skan
912169689Skan/* After live values has been marked, walk all recorded pointers and see if
913169689Skan   they are still live.  */
914169689Skanvoid
915169689Skanggc_prune_overhead_list (void)
916169689Skan{
917169689Skan  htab_traverse (ptr_hash, ggc_prune_ptr, NULL);
918169689Skan}
919169689Skan
920169689Skan/* Notice that the pointer has been freed.  */
921169689Skanvoid
922169689Skanggc_free_overhead (void *ptr)
923169689Skan{
924169689Skan  PTR *slot = htab_find_slot_with_hash (ptr_hash, ptr, htab_hash_pointer (ptr),
925169689Skan					NO_INSERT);
926169689Skan  struct ptr_hash_entry *p = *slot;
927169689Skan  p->loc->freed += p->size;
928169689Skan  htab_clear_slot (ptr_hash, slot);
929169689Skan  free (p);
930169689Skan}
931169689Skan
932169689Skan/* Helper for qsort; sort descriptors by amount of memory consumed.  */
933169689Skanstatic int
934169689Skancmp_statistic (const void *loc1, const void *loc2)
935169689Skan{
936169689Skan  struct loc_descriptor *l1 = *(struct loc_descriptor **) loc1;
937169689Skan  struct loc_descriptor *l2 = *(struct loc_descriptor **) loc2;
938169689Skan  return ((l1->allocated + l1->overhead - l1->freed) -
939169689Skan	  (l2->allocated + l2->overhead - l2->freed));
940169689Skan}
941169689Skan
942169689Skan/* Collect array of the descriptors from hashtable.  */
943169689Skanstruct loc_descriptor **loc_array;
944169689Skanstatic int
945169689Skanadd_statistics (void **slot, void *b)
946169689Skan{
947169689Skan  int *n = (int *)b;
948169689Skan  loc_array[*n] = (struct loc_descriptor *) *slot;
949169689Skan  (*n)++;
950169689Skan  return 1;
951169689Skan}
952169689Skan
953169689Skan/* Dump per-site memory statistics.  */
954169689Skan#endif
955169689Skanvoid
956169689Skandump_ggc_loc_statistics (void)
957169689Skan{
958169689Skan#ifdef GATHER_STATISTICS
959169689Skan  int nentries = 0;
960169689Skan  char s[4096];
961169689Skan  size_t collected = 0, freed = 0, allocated = 0, overhead = 0, times = 0;
962169689Skan  int i;
963169689Skan
964169689Skan  ggc_force_collect = true;
965169689Skan  ggc_collect ();
966169689Skan
967169689Skan  loc_array = xcalloc (sizeof (*loc_array), loc_hash->n_elements);
968169689Skan  fprintf (stderr, "-------------------------------------------------------\n");
969169689Skan  fprintf (stderr, "\n%-48s %10s       %10s       %10s       %10s       %10s\n",
970169689Skan	   "source location", "Garbage", "Freed", "Leak", "Overhead", "Times");
971169689Skan  fprintf (stderr, "-------------------------------------------------------\n");
972169689Skan  htab_traverse (loc_hash, add_statistics, &nentries);
973169689Skan  qsort (loc_array, nentries, sizeof (*loc_array), cmp_statistic);
974169689Skan  for (i = 0; i < nentries; i++)
975169689Skan    {
976169689Skan      struct loc_descriptor *d = loc_array[i];
977169689Skan      allocated += d->allocated;
978169689Skan      times += d->times;
979169689Skan      freed += d->freed;
980169689Skan      collected += d->collected;
981169689Skan      overhead += d->overhead;
982169689Skan    }
983169689Skan  for (i = 0; i < nentries; i++)
984169689Skan    {
985169689Skan      struct loc_descriptor *d = loc_array[i];
986169689Skan      if (d->allocated)
987169689Skan	{
988169689Skan	  const char *s1 = d->file;
989169689Skan	  const char *s2;
990169689Skan	  while ((s2 = strstr (s1, "gcc/")))
991169689Skan	    s1 = s2 + 4;
992169689Skan	  sprintf (s, "%s:%i (%s)", s1, d->line, d->function);
993169689Skan	  s[48] = 0;
994169689Skan	  fprintf (stderr, "%-48s %10li:%4.1f%% %10li:%4.1f%% %10li:%4.1f%% %10li:%4.1f%% %10li\n", s,
995169689Skan		   (long)d->collected,
996169689Skan		   (d->collected) * 100.0 / collected,
997169689Skan		   (long)d->freed,
998169689Skan		   (d->freed) * 100.0 / freed,
999169689Skan		   (long)(d->allocated + d->overhead - d->freed - d->collected),
1000169689Skan		   (d->allocated + d->overhead - d->freed - d->collected) * 100.0
1001169689Skan		   / (allocated + overhead - freed - collected),
1002169689Skan		   (long)d->overhead,
1003169689Skan		   d->overhead * 100.0 / overhead,
1004169689Skan		   (long)d->times);
1005169689Skan	}
1006169689Skan    }
1007169689Skan  fprintf (stderr, "%-48s %10ld       %10ld       %10ld       %10ld       %10ld\n",
1008169689Skan	   "Total", (long)collected, (long)freed,
1009169689Skan	   (long)(allocated + overhead - freed - collected), (long)overhead,
1010169689Skan	   (long)times);
1011169689Skan  fprintf (stderr, "%-48s %10s       %10s       %10s       %10s       %10s\n",
1012169689Skan	   "source location", "Garbage", "Freed", "Leak", "Overhead", "Times");
1013169689Skan  fprintf (stderr, "-------------------------------------------------------\n");
1014169689Skan#endif
1015169689Skan}
1016