OSDN Git Service

* cpppch.c (reset_ht): Remove.
[pf3gnuchains/gcc-fork.git] / gcc / ggc-common.c
1 /* Simple garbage collection for the GNU compiler.
2    Copyright (C) 1999, 2000, 2001, 2002, 2003
3    Free Software Foundation, Inc.
4
5 This file is part of GCC.
6
7 GCC is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 2, or (at your option) any later
10 version.
11
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15 for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING.  If not, write to the Free
19 Software Foundation, 59 Temple Place - Suite 330, Boston, MA
20 02111-1307, USA.  */
21
22 /* Generic garbage collection (GC) functions and data, not specific to
23    any particular GC implementation.  */
24
25 #include "config.h"
26 #include "system.h"
27 #include "coretypes.h"
28 #include "hashtab.h"
29 #include "ggc.h"
30 #include "toplev.h"
31 #include "params.h"
32
33 #ifdef HAVE_SYS_RESOURCE_H
34 # include <sys/resource.h>
35 #endif
36
37 #ifdef HAVE_MMAP_FILE
38 # include <sys/mman.h>
39 #endif
40
41 #ifdef ENABLE_VALGRIND_CHECKING
42 # ifdef HAVE_MEMCHECK_H
43 # include <memcheck.h>
44 # else
45 # include <valgrind.h>
46 # endif
47 #else
48 /* Avoid #ifdef:s when we can help it.  */
49 #define VALGRIND_DISCARD(x)
50 #endif
51
52 /* Statistics about the allocation.  */
53 static ggc_statistics *ggc_stats;
54
55 struct traversal_state;
56
57 static int ggc_htab_delete PARAMS ((void **, void *));
58 static hashval_t saving_htab_hash PARAMS ((const PTR));
59 static int saving_htab_eq PARAMS ((const PTR, const PTR));
60 static int call_count PARAMS ((void **, void *));
61 static int call_alloc PARAMS ((void **, void *));
62 static int compare_ptr_data PARAMS ((const void *, const void *));
63 static void relocate_ptrs PARAMS ((void *, void *));
64 static void write_pch_globals PARAMS ((const struct ggc_root_tab * const *tab,
65                                        struct traversal_state *state));
66 static double ggc_rlimit_bound PARAMS ((double));
67
68 /* Maintain global roots that are preserved during GC.  */
69
70 /* Process a slot of an htab by deleting it if it has not been marked.  */
71
72 static int
73 ggc_htab_delete (slot, info)
74      void **slot;
75      void *info;
76 {
77   const struct ggc_cache_tab *r = (const struct ggc_cache_tab *) info;
78
79   if (! (*r->marked_p) (*slot))
80     htab_clear_slot (*r->base, slot);
81   else
82     (*r->cb) (*slot);
83
84   return 1;
85 }
86
87 /* Iterate through all registered roots and mark each element.  */
88
89 void
90 ggc_mark_roots ()
91 {
92   const struct ggc_root_tab *const *rt;
93   const struct ggc_root_tab *rti;
94   const struct ggc_cache_tab *const *ct;
95   const struct ggc_cache_tab *cti;
96   size_t i;
97
98   for (rt = gt_ggc_deletable_rtab; *rt; rt++)
99     for (rti = *rt; rti->base != NULL; rti++)
100       memset (rti->base, 0, rti->stride);
101
102   for (rt = gt_ggc_rtab; *rt; rt++)
103     for (rti = *rt; rti->base != NULL; rti++)
104       for (i = 0; i < rti->nelt; i++)
105         (*rti->cb)(*(void **)((char *)rti->base + rti->stride * i));
106
107   ggc_mark_stringpool ();
108
109   /* Now scan all hash tables that have objects which are to be deleted if
110      they are not already marked.  */
111   for (ct = gt_ggc_cache_rtab; *ct; ct++)
112     for (cti = *ct; cti->base != NULL; cti++)
113       if (*cti->base)
114         {
115           ggc_set_mark (*cti->base);
116           htab_traverse_noresize (*cti->base, ggc_htab_delete, (PTR) cti);
117           ggc_set_mark ((*cti->base)->entries);
118         }
119 }
120
121 /* Allocate a block of memory, then clear it.  */
122 void *
123 ggc_alloc_cleared (size)
124      size_t size;
125 {
126   void *buf = ggc_alloc (size);
127   memset (buf, 0, size);
128   return buf;
129 }
130
131 /* Resize a block of memory, possibly re-allocating it.  */
132 void *
133 ggc_realloc (x, size)
134      void *x;
135      size_t size;
136 {
137   void *r;
138   size_t old_size;
139
140   if (x == NULL)
141     return ggc_alloc (size);
142
143   old_size = ggc_get_size (x);
144   if (size <= old_size)
145     {
146       /* Mark the unwanted memory as unaccessible.  We also need to make
147          the "new" size accessible, since ggc_get_size returns the size of
148          the pool, not the size of the individually allocated object, the
149          size which was previously made accessible.  Unfortunately, we
150          don't know that previously allocated size.  Without that
151          knowledge we have to lose some initialization-tracking for the
152          old parts of the object.  An alternative is to mark the whole
153          old_size as reachable, but that would lose tracking of writes 
154          after the end of the object (by small offsets).  Discard the
155          handle to avoid handle leak.  */
156       VALGRIND_DISCARD (VALGRIND_MAKE_NOACCESS ((char *) x + size,
157                                                 old_size - size));
158       VALGRIND_DISCARD (VALGRIND_MAKE_READABLE (x, size));
159       return x;
160     }
161
162   r = ggc_alloc (size);
163
164   /* Since ggc_get_size returns the size of the pool, not the size of the
165      individually allocated object, we'd access parts of the old object
166      that were marked invalid with the memcpy below.  We lose a bit of the
167      initialization-tracking since some of it may be uninitialized.  */
168   VALGRIND_DISCARD (VALGRIND_MAKE_READABLE (x, old_size));
169
170   memcpy (r, x, old_size);
171
172   /* The old object is not supposed to be used anymore.  */
173   VALGRIND_DISCARD (VALGRIND_MAKE_NOACCESS (x, old_size));
174
175   return r;
176 }
177
178 /* Like ggc_alloc_cleared, but performs a multiplication.  */
179 void *
180 ggc_calloc (s1, s2)
181      size_t s1, s2;
182 {
183   return ggc_alloc_cleared (s1 * s2);
184 }
185
186 /* These are for splay_tree_new_ggc.  */
187 PTR 
188 ggc_splay_alloc (sz, nl)
189      int sz;
190      PTR nl;
191 {
192   if (nl != NULL)
193     abort ();
194   return ggc_alloc (sz);
195 }
196
197 void
198 ggc_splay_dont_free (x, nl)
199      PTR x ATTRIBUTE_UNUSED;
200      PTR nl;
201 {
202   if (nl != NULL)
203     abort ();
204 }
205
206 /* Print statistics that are independent of the collector in use.  */
207 #define SCALE(x) ((unsigned long) ((x) < 1024*10 \
208                   ? (x) \
209                   : ((x) < 1024*1024*10 \
210                      ? (x) / 1024 \
211                      : (x) / (1024*1024))))
212 #define LABEL(x) ((x) < 1024*10 ? ' ' : ((x) < 1024*1024*10 ? 'k' : 'M'))
213
214 void
215 ggc_print_common_statistics (stream, stats)
216      FILE *stream ATTRIBUTE_UNUSED;
217      ggc_statistics *stats;
218 {
219   /* Set the pointer so that during collection we will actually gather
220      the statistics.  */
221   ggc_stats = stats;
222
223   /* Then do one collection to fill in the statistics.  */
224   ggc_collect ();
225
226   /* At present, we don't really gather any interesting statistics.  */
227
228   /* Don't gather statistics any more.  */
229   ggc_stats = NULL;
230 }
231 \f
232 /* Functions for saving and restoring GCable memory to disk.  */
233
234 static htab_t saving_htab;
235
236 struct ptr_data 
237 {
238   void *obj;
239   void *note_ptr_cookie;
240   gt_note_pointers note_ptr_fn;
241   gt_handle_reorder reorder_fn;
242   size_t size;
243   void *new_addr;
244 };
245
246 #define POINTER_HASH(x) (hashval_t)((long)x >> 3)
247
248 /* Register an object in the hash table.  */
249
250 int
251 gt_pch_note_object (obj, note_ptr_cookie, note_ptr_fn)
252      void *obj;
253      void *note_ptr_cookie;
254      gt_note_pointers note_ptr_fn;
255 {
256   struct ptr_data **slot;
257   
258   if (obj == NULL || obj == (void *) 1)
259     return 0;
260
261   slot = (struct ptr_data **)
262     htab_find_slot_with_hash (saving_htab, obj, POINTER_HASH (obj),
263                               INSERT);
264   if (*slot != NULL)
265     {
266       if ((*slot)->note_ptr_fn != note_ptr_fn
267           || (*slot)->note_ptr_cookie != note_ptr_cookie)
268         abort ();
269       return 0;
270     }
271   
272   *slot = xcalloc (sizeof (struct ptr_data), 1);
273   (*slot)->obj = obj;
274   (*slot)->note_ptr_fn = note_ptr_fn;
275   (*slot)->note_ptr_cookie = note_ptr_cookie;
276   if (note_ptr_fn == gt_pch_p_S)
277     (*slot)->size = strlen (obj) + 1;
278   else
279     (*slot)->size = ggc_get_size (obj);
280   return 1;
281 }
282
283 /* Register an object in the hash table.  */
284
285 void
286 gt_pch_note_reorder (obj, note_ptr_cookie, reorder_fn)
287      void *obj;
288      void *note_ptr_cookie;
289      gt_handle_reorder reorder_fn;
290 {
291   struct ptr_data *data;
292   
293   if (obj == NULL || obj == (void *) 1)
294     return;
295
296   data = htab_find_with_hash (saving_htab, obj, POINTER_HASH (obj));
297   if (data == NULL
298       || data->note_ptr_cookie != note_ptr_cookie)
299     abort ();
300   
301   data->reorder_fn = reorder_fn;
302 }
303
304 /* Hash and equality functions for saving_htab, callbacks for htab_create.  */
305
306 static hashval_t
307 saving_htab_hash (p)
308      const PTR p;
309 {
310   return POINTER_HASH (((struct ptr_data *)p)->obj);
311 }
312
313 static int
314 saving_htab_eq (p1, p2)
315      const PTR p1;
316      const PTR p2;
317 {
318   return ((struct ptr_data *)p1)->obj == p2;
319 }
320
321 /* Handy state for the traversal functions.  */
322
323 struct traversal_state 
324 {
325   FILE *f;
326   struct ggc_pch_data *d;
327   size_t count;
328   struct ptr_data **ptrs;
329   size_t ptrs_i;
330 };
331
332 /* Callbacks for htab_traverse.  */
333
334 static int
335 call_count (slot, state_p)
336      void **slot;
337      void *state_p;
338 {
339   struct ptr_data *d = (struct ptr_data *)*slot;
340   struct traversal_state *state = (struct traversal_state *)state_p;
341   
342   ggc_pch_count_object (state->d, d->obj, d->size);
343   state->count++;
344   return 1;
345 }
346
347 static int
348 call_alloc (slot, state_p)
349      void **slot;
350      void *state_p;
351 {
352   struct ptr_data *d = (struct ptr_data *)*slot;
353   struct traversal_state *state = (struct traversal_state *)state_p;
354   
355   d->new_addr = ggc_pch_alloc_object (state->d, d->obj, d->size);
356   state->ptrs[state->ptrs_i++] = d;
357   return 1;
358 }
359
360 /* Callback for qsort.  */
361
362 static int
363 compare_ptr_data (p1_p, p2_p)
364      const void *p1_p;
365      const void *p2_p;
366 {
367   struct ptr_data *p1 = *(struct ptr_data *const *)p1_p;
368   struct ptr_data *p2 = *(struct ptr_data *const *)p2_p;
369   return (((size_t)p1->new_addr > (size_t)p2->new_addr)
370           - ((size_t)p1->new_addr < (size_t)p2->new_addr));
371 }
372
373 /* Callbacks for note_ptr_fn.  */
374
375 static void
376 relocate_ptrs (ptr_p, state_p)
377      void *ptr_p;
378      void *state_p;
379 {
380   void **ptr = (void **)ptr_p;
381   struct traversal_state *state ATTRIBUTE_UNUSED 
382     = (struct traversal_state *)state_p;
383   struct ptr_data *result;
384
385   if (*ptr == NULL || *ptr == (void *)1)
386     return;
387   
388   result = htab_find_with_hash (saving_htab, *ptr, POINTER_HASH (*ptr));
389   if (result == NULL)
390     abort ();
391   *ptr = result->new_addr;
392 }
393
394 /* Write out, after relocation, the pointers in TAB.  */
395 static void
396 write_pch_globals (tab, state)
397      const struct ggc_root_tab * const *tab;
398      struct traversal_state *state;
399 {
400   const struct ggc_root_tab *const *rt;
401   const struct ggc_root_tab *rti;
402   size_t i;
403
404   for (rt = tab; *rt; rt++)
405     for (rti = *rt; rti->base != NULL; rti++)
406       for (i = 0; i < rti->nelt; i++)
407         {
408           void *ptr = *(void **)((char *)rti->base + rti->stride * i);
409           struct ptr_data *new_ptr;
410           if (ptr == NULL || ptr == (void *)1)
411             {
412               if (fwrite (&ptr, sizeof (void *), 1, state->f) 
413                   != 1)
414                 fatal_io_error ("can't write PCH file");
415             }
416           else
417             {
418               new_ptr = htab_find_with_hash (saving_htab, ptr, 
419                                              POINTER_HASH (ptr));
420               if (fwrite (&new_ptr->new_addr, sizeof (void *), 1, state->f) 
421                   != 1)
422                 fatal_io_error ("can't write PCH file");
423             }
424         }
425 }
426
427 /* Hold the information we need to mmap the file back in.  */
428
429 struct mmap_info 
430 {
431   size_t offset;
432   size_t size;
433   void *preferred_base;
434 };
435
436 /* Write out the state of the compiler to F.  */
437
438 void
439 gt_pch_save (f)
440      FILE *f;
441 {
442   const struct ggc_root_tab *const *rt;
443   const struct ggc_root_tab *rti;
444   size_t i;
445   struct traversal_state state;
446   char *this_object = NULL;
447   size_t this_object_size = 0;
448   struct mmap_info mmi;
449   size_t page_size = getpagesize();
450
451   gt_pch_save_stringpool ();
452
453   saving_htab = htab_create (50000, saving_htab_hash, saving_htab_eq, free);
454
455   for (rt = gt_ggc_rtab; *rt; rt++)
456     for (rti = *rt; rti->base != NULL; rti++)
457       for (i = 0; i < rti->nelt; i++)
458         (*rti->pchw)(*(void **)((char *)rti->base + rti->stride * i));
459
460   for (rt = gt_pch_cache_rtab; *rt; rt++)
461     for (rti = *rt; rti->base != NULL; rti++)
462       for (i = 0; i < rti->nelt; i++)
463         (*rti->pchw)(*(void **)((char *)rti->base + rti->stride * i));
464
465   /* Prepare the objects for writing, determine addresses and such.  */
466   state.f = f;
467   state.d = init_ggc_pch();
468   state.count = 0;
469   htab_traverse (saving_htab, call_count, &state);
470
471   mmi.size = ggc_pch_total_size (state.d);
472
473   /* Try to arrange things so that no relocation is necessary,
474      but don't try very hard.  On most platforms, this will always work,
475      and on the rest it's a lot of work to do better.  */
476 #if HAVE_MMAP_FILE
477   mmi.preferred_base = mmap (NULL, mmi.size, 
478                              PROT_READ | PROT_WRITE, MAP_PRIVATE,
479                              fileno (state.f), 0);
480   if (mmi.preferred_base == (void *)-1)
481     mmi.preferred_base = NULL;
482   else
483     munmap (mmi.preferred_base, mmi.size);
484 #else /* HAVE_MMAP_FILE */
485   mmi.preferred_base = NULL;
486 #endif /* HAVE_MMAP_FILE */
487
488   ggc_pch_this_base (state.d, mmi.preferred_base);
489
490   state.ptrs = xmalloc (state.count * sizeof (*state.ptrs));
491   state.ptrs_i = 0;
492   htab_traverse (saving_htab, call_alloc, &state);
493   qsort (state.ptrs, state.count, sizeof (*state.ptrs), compare_ptr_data);
494
495   /* Write out all the scalar variables.  */
496   for (rt = gt_pch_scalar_rtab; *rt; rt++)
497     for (rti = *rt; rti->base != NULL; rti++)
498       if (fwrite (rti->base, rti->stride, 1, f) != 1)
499         fatal_io_error ("can't write PCH file");
500
501   /* Write out all the global pointers, after translation.  */
502   write_pch_globals (gt_ggc_rtab, &state);
503   write_pch_globals (gt_pch_cache_rtab, &state);
504
505   ggc_pch_prepare_write (state.d, state.f);
506   
507   /* Pad the PCH file so that the mmaped area starts on a page boundary.  */
508   {
509     long o;
510     o = ftell (state.f) + sizeof (mmi);
511     if (o == -1)
512       fatal_io_error ("can't get position in PCH file");
513     mmi.offset = page_size - o % page_size;
514     if (mmi.offset == page_size)
515       mmi.offset = 0;
516     mmi.offset += o;
517   }
518   if (fwrite (&mmi, sizeof (mmi), 1, state.f) != 1)
519     fatal_io_error ("can't write PCH file");
520   if (mmi.offset != 0
521       && fseek (state.f, mmi.offset, SEEK_SET) != 0)
522     fatal_io_error ("can't write padding to PCH file");
523
524   /* Actually write out the objects.  */
525   for (i = 0; i < state.count; i++)
526     {
527       if (this_object_size < state.ptrs[i]->size)
528         {
529           this_object_size = state.ptrs[i]->size;
530           this_object = xrealloc (this_object, this_object_size);
531         }
532       memcpy (this_object, state.ptrs[i]->obj, state.ptrs[i]->size);
533       if (state.ptrs[i]->reorder_fn != NULL)
534         state.ptrs[i]->reorder_fn (state.ptrs[i]->obj, 
535                                    state.ptrs[i]->note_ptr_cookie,
536                                    relocate_ptrs, &state);
537       state.ptrs[i]->note_ptr_fn (state.ptrs[i]->obj, 
538                                   state.ptrs[i]->note_ptr_cookie,
539                                   relocate_ptrs, &state);
540       ggc_pch_write_object (state.d, state.f, state.ptrs[i]->obj,
541                             state.ptrs[i]->new_addr, state.ptrs[i]->size);
542       if (state.ptrs[i]->note_ptr_fn != gt_pch_p_S)
543         memcpy (state.ptrs[i]->obj, this_object, state.ptrs[i]->size);
544     }
545   ggc_pch_finish (state.d, state.f);
546   gt_pch_fixup_stringpool ();
547
548   free (state.ptrs);
549   htab_delete (saving_htab);
550 }
551
552 /* Read the state of the compiler back in from F.  */
553
554 void
555 gt_pch_restore (f)
556      FILE *f;
557 {
558   const struct ggc_root_tab *const *rt;
559   const struct ggc_root_tab *rti;
560   size_t i;
561   struct mmap_info mmi;
562   void *addr;
563
564   /* Delete any deletable objects.  This makes ggc_pch_read much
565      faster, as it can be sure that no GCable objects remain other
566      than the ones just read in.  */
567   for (rt = gt_ggc_deletable_rtab; *rt; rt++)
568     for (rti = *rt; rti->base != NULL; rti++)
569       memset (rti->base, 0, rti->stride);
570
571   /* Read in all the scalar variables.  */
572   for (rt = gt_pch_scalar_rtab; *rt; rt++)
573     for (rti = *rt; rti->base != NULL; rti++)
574       if (fread (rti->base, rti->stride, 1, f) != 1)
575         fatal_io_error ("can't read PCH file");
576
577   /* Read in all the global pointers, in 6 easy loops.  */
578   for (rt = gt_ggc_rtab; *rt; rt++)
579     for (rti = *rt; rti->base != NULL; rti++)
580       for (i = 0; i < rti->nelt; i++)
581         if (fread ((char *)rti->base + rti->stride * i,
582                    sizeof (void *), 1, f) != 1)
583           fatal_io_error ("can't read PCH file");
584
585   for (rt = gt_pch_cache_rtab; *rt; rt++)
586     for (rti = *rt; rti->base != NULL; rti++)
587       for (i = 0; i < rti->nelt; i++)
588         if (fread ((char *)rti->base + rti->stride * i,
589                    sizeof (void *), 1, f) != 1)
590           fatal_io_error ("can't read PCH file");
591
592   if (fread (&mmi, sizeof (mmi), 1, f) != 1)
593     fatal_io_error ("can't read PCH file");
594   
595 #if HAVE_MMAP_FILE
596   addr = mmap (mmi.preferred_base, mmi.size, 
597                PROT_READ | PROT_WRITE, MAP_PRIVATE,
598                fileno (f), mmi.offset);
599 #else
600   addr = (void *)-1;
601 #endif
602   if (addr == (void *)-1)
603     {
604       addr = xmalloc (mmi.size);
605       if (fseek (f, mmi.offset, SEEK_SET) != 0
606           || fread (&mmi, mmi.size, 1, f) != 1)
607         fatal_io_error ("can't read PCH file");
608     }
609   else if (fseek (f, mmi.offset + mmi.size, SEEK_SET) != 0)
610     fatal_io_error ("can't read PCH file");
611
612   ggc_pch_read (f, addr);
613
614   if (addr != mmi.preferred_base)
615     {
616       for (rt = gt_ggc_rtab; *rt; rt++)
617         for (rti = *rt; rti->base != NULL; rti++)
618           for (i = 0; i < rti->nelt; i++)
619             {
620               char **ptr = (char **)((char *)rti->base + rti->stride * i);
621               if (*ptr != NULL)
622                 *ptr += (size_t)addr - (size_t)mmi.preferred_base;
623             }
624       
625       for (rt = gt_pch_cache_rtab; *rt; rt++)
626         for (rti = *rt; rti->base != NULL; rti++)
627           for (i = 0; i < rti->nelt; i++)
628             {
629               char **ptr = (char **)((char *)rti->base + rti->stride * i);
630               if (*ptr != NULL)
631                 *ptr += (size_t)addr - (size_t)mmi.preferred_base;
632             }
633
634       sorry ("had to relocate PCH");
635     }
636
637   gt_pch_restore_stringpool ();
638 }
639
640 /* Modify the bound based on rlimits.  Keep the smallest number found.  */
641 static double
642 ggc_rlimit_bound (limit)
643      double limit;
644 {
645 #if defined(HAVE_GETRLIMIT)
646   struct rlimit rlim;
647 # ifdef RLIMIT_RSS
648   if (getrlimit (RLIMIT_RSS, &rlim) == 0
649       && rlim.rlim_cur != (rlim_t) RLIM_INFINITY
650       && rlim.rlim_cur < limit)
651     limit = rlim.rlim_cur;
652 # endif
653 # ifdef RLIMIT_DATA
654   if (getrlimit (RLIMIT_DATA, &rlim) == 0
655       && rlim.rlim_cur != (rlim_t) RLIM_INFINITY
656       && rlim.rlim_cur < limit)
657     limit = rlim.rlim_cur;
658 # endif
659 # ifdef RLIMIT_AS
660   if (getrlimit (RLIMIT_AS, &rlim) == 0
661       && rlim.rlim_cur != (rlim_t) RLIM_INFINITY
662       && rlim.rlim_cur < limit)
663     limit = rlim.rlim_cur;
664 # endif
665 #endif /* HAVE_GETRLIMIT */
666
667   return limit;
668 }
669
670 /* Heuristic to set a default for GGC_MIN_EXPAND.  */
671 int
672 ggc_min_expand_heuristic()
673 {
674   double min_expand = physmem_total();
675
676   /* Adjust for rlimits.  */
677   min_expand = ggc_rlimit_bound (min_expand);
678   
679   /* The heuristic is a percentage equal to 30% + 70%*(RAM/1GB), yielding
680      a lower bound of 30% and an upper bound of 100% (when RAM >= 1GB).  */
681   min_expand /= 1024*1024*1024;
682   min_expand *= 70;
683   min_expand = MIN (min_expand, 70);
684   min_expand += 30;
685
686   return min_expand;
687 }
688
689 /* Heuristic to set a default for GGC_MIN_HEAPSIZE.  */
690 int
691 ggc_min_heapsize_heuristic()
692 {
693   double min_heap_kbytes = physmem_total();
694
695   /* Adjust for rlimits.  */
696   min_heap_kbytes = ggc_rlimit_bound (min_heap_kbytes);
697
698   min_heap_kbytes /= 1024; /* convert to Kbytes.  */
699   
700   /* The heuristic is RAM/8, with a lower bound of 4M and an upper
701      bound of 128M (when RAM >= 1GB).  */
702   min_heap_kbytes /= 8;
703   min_heap_kbytes = MAX (min_heap_kbytes, 4 * 1024);
704   min_heap_kbytes = MIN (min_heap_kbytes, 128 * 1024);
705
706   return min_heap_kbytes;
707 }
708
709 void
710 init_ggc_heuristics ()
711 {
712 #ifndef ENABLE_GC_ALWAYS_COLLECT
713   set_param_value ("ggc-min-expand", ggc_min_expand_heuristic());
714   set_param_value ("ggc-min-heapsize", ggc_min_heapsize_heuristic());
715 #endif
716 }