OSDN Git Service

b1c3c61bb2cc1f687570c92c618094638ba14522
[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
547   free (state.ptrs);
548   htab_delete (saving_htab);
549 }
550
551 /* Read the state of the compiler back in from F.  */
552
553 void
554 gt_pch_restore (f)
555      FILE *f;
556 {
557   const struct ggc_root_tab *const *rt;
558   const struct ggc_root_tab *rti;
559   size_t i;
560   struct mmap_info mmi;
561   void *addr;
562
563   /* Delete any deletable objects.  This makes ggc_pch_read much
564      faster, as it can be sure that no GCable objects remain other
565      than the ones just read in.  */
566   for (rt = gt_ggc_deletable_rtab; *rt; rt++)
567     for (rti = *rt; rti->base != NULL; rti++)
568       memset (rti->base, 0, rti->stride);
569
570   /* Read in all the scalar variables.  */
571   for (rt = gt_pch_scalar_rtab; *rt; rt++)
572     for (rti = *rt; rti->base != NULL; rti++)
573       if (fread (rti->base, rti->stride, 1, f) != 1)
574         fatal_io_error ("can't read PCH file");
575
576   /* Read in all the global pointers, in 6 easy loops.  */
577   for (rt = gt_ggc_rtab; *rt; rt++)
578     for (rti = *rt; rti->base != NULL; rti++)
579       for (i = 0; i < rti->nelt; i++)
580         if (fread ((char *)rti->base + rti->stride * i,
581                    sizeof (void *), 1, f) != 1)
582           fatal_io_error ("can't read PCH file");
583
584   for (rt = gt_pch_cache_rtab; *rt; rt++)
585     for (rti = *rt; rti->base != NULL; rti++)
586       for (i = 0; i < rti->nelt; i++)
587         if (fread ((char *)rti->base + rti->stride * i,
588                    sizeof (void *), 1, f) != 1)
589           fatal_io_error ("can't read PCH file");
590
591   if (fread (&mmi, sizeof (mmi), 1, f) != 1)
592     fatal_io_error ("can't read PCH file");
593   
594 #if HAVE_MMAP_FILE
595   addr = mmap (mmi.preferred_base, mmi.size, 
596                PROT_READ | PROT_WRITE, MAP_PRIVATE,
597                fileno (f), mmi.offset);
598 #else
599   addr = (void *)-1;
600 #endif
601   if (addr == (void *)-1)
602     {
603       addr = xmalloc (mmi.size);
604       if (fseek (f, mmi.offset, SEEK_SET) != 0
605           || fread (&mmi, mmi.size, 1, f) != 1)
606         fatal_io_error ("can't read PCH file");
607     }
608   else if (fseek (f, mmi.offset + mmi.size, SEEK_SET) != 0)
609     fatal_io_error ("can't read PCH file");
610
611   ggc_pch_read (f, addr);
612
613   if (addr != mmi.preferred_base)
614     {
615       for (rt = gt_ggc_rtab; *rt; rt++)
616         for (rti = *rt; rti->base != NULL; rti++)
617           for (i = 0; i < rti->nelt; i++)
618             {
619               char **ptr = (char **)((char *)rti->base + rti->stride * i);
620               if (*ptr != NULL)
621                 *ptr += (size_t)addr - (size_t)mmi.preferred_base;
622             }
623       
624       for (rt = gt_pch_cache_rtab; *rt; rt++)
625         for (rti = *rt; rti->base != NULL; rti++)
626           for (i = 0; i < rti->nelt; i++)
627             {
628               char **ptr = (char **)((char *)rti->base + rti->stride * i);
629               if (*ptr != NULL)
630                 *ptr += (size_t)addr - (size_t)mmi.preferred_base;
631             }
632
633       sorry ("had to relocate PCH");
634     }
635
636   gt_pch_restore_stringpool ();
637 }
638
639 /* Modify the bound based on rlimits.  Keep the smallest number found.  */
640 static double
641 ggc_rlimit_bound (limit)
642      double limit;
643 {
644 #if defined(HAVE_GETRLIMIT)
645   struct rlimit rlim;
646 # ifdef RLIMIT_RSS
647   if (getrlimit (RLIMIT_RSS, &rlim) == 0
648       && rlim.rlim_cur != (rlim_t) RLIM_INFINITY
649       && rlim.rlim_cur < limit)
650     limit = rlim.rlim_cur;
651 # endif
652 # ifdef RLIMIT_DATA
653   if (getrlimit (RLIMIT_DATA, &rlim) == 0
654       && rlim.rlim_cur != (rlim_t) RLIM_INFINITY
655       && rlim.rlim_cur < limit)
656     limit = rlim.rlim_cur;
657 # endif
658 # ifdef RLIMIT_AS
659   if (getrlimit (RLIMIT_AS, &rlim) == 0
660       && rlim.rlim_cur != (rlim_t) RLIM_INFINITY
661       && rlim.rlim_cur < limit)
662     limit = rlim.rlim_cur;
663 # endif
664 #endif /* HAVE_GETRLIMIT */
665
666   return limit;
667 }
668
669 /* Heuristic to set a default for GGC_MIN_EXPAND.  */
670 int
671 ggc_min_expand_heuristic()
672 {
673   double min_expand = physmem_total();
674
675   /* Adjust for rlimits.  */
676   min_expand = ggc_rlimit_bound (min_expand);
677   
678   /* The heuristic is a percentage equal to 30% + 70%*(RAM/1GB), yielding
679      a lower bound of 30% and an upper bound of 100% (when RAM >= 1GB).  */
680   min_expand /= 1024*1024*1024;
681   min_expand *= 70;
682   min_expand = MIN (min_expand, 70);
683   min_expand += 30;
684
685   return min_expand;
686 }
687
688 /* Heuristic to set a default for GGC_MIN_HEAPSIZE.  */
689 int
690 ggc_min_heapsize_heuristic()
691 {
692   double min_heap_kbytes = physmem_total();
693
694   /* Adjust for rlimits.  */
695   min_heap_kbytes = ggc_rlimit_bound (min_heap_kbytes);
696
697   min_heap_kbytes /= 1024; /* convert to Kbytes.  */
698   
699   /* The heuristic is RAM/8, with a lower bound of 4M and an upper
700      bound of 128M (when RAM >= 1GB).  */
701   min_heap_kbytes /= 8;
702   min_heap_kbytes = MAX (min_heap_kbytes, 4 * 1024);
703   min_heap_kbytes = MIN (min_heap_kbytes, 128 * 1024);
704
705   return min_heap_kbytes;
706 }
707
708 void
709 init_ggc_heuristics ()
710 {
711 #ifndef ENABLE_GC_ALWAYS_COLLECT
712   set_param_value ("ggc-min-expand", ggc_min_expand_heuristic());
713   set_param_value ("ggc-min-heapsize", ggc_min_heapsize_heuristic());
714 #endif
715 }